summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/client.go33
-rw-r--r--client/client_test.go2
-rw-r--r--client/fsm.go13
-rw-r--r--client/proxy.go4
-rw-r--r--client/token.go12
-rw-r--r--cmd/cli/main.go1
-rw-r--r--exports/exports.go20
-rw-r--r--i18nerr/i18nerr.go4
-rw-r--r--internal/api/api.go32
-rw-r--r--internal/api/endpoints/endpoints.go17
-rw-r--r--internal/api/profiles/profiles.go39
-rw-r--r--internal/config/config.go12
-rw-r--r--internal/config/v1/v1.go61
-rw-r--r--internal/config/v2/convert.go13
-rw-r--r--internal/config/v2/v2.go67
-rw-r--r--internal/config/v2/v2_test.go4
-rw-r--r--internal/discovery/discovery.go8
-rw-r--r--internal/failover/failover.go2
-rw-r--r--internal/failover/monitor.go4
-rw-r--r--internal/failover/ping.go3
-rw-r--r--internal/failover/ping_default.go1
-rw-r--r--internal/fsm/fsm.go10
-rw-r--r--internal/http/http.go4
-rw-r--r--internal/log/log.go3
-rw-r--r--internal/server/custom.go9
-rw-r--r--internal/server/institute.go11
-rw-r--r--internal/server/secureinternet.go11
-rw-r--r--internal/server/server.go13
-rw-r--r--internal/server/servers.go36
-rw-r--r--internal/server/time.go3
-rw-r--r--internal/test/error.go1
-rw-r--r--internal/test/handler.go2
-rw-r--r--internal/test/server.go3
-rw-r--r--internal/version/version.go6
-rw-r--r--internal/wireguard/ini/ini.go2
-rw-r--r--internal/wireguard/wireguard.go9
-rw-r--r--types/cookie/cookie.go6
-rw-r--r--types/discovery/discovery.go4
-rw-r--r--types/error/error.go1
-rw-r--r--types/protocol/protocol.go2
-rw-r--r--types/server/server.go4
41 files changed, 382 insertions, 110 deletions
diff --git a/client/client.go b/client/client.go
index 07287cf..f00d56e 100644
--- a/client/client.go
+++ b/client/client.go
@@ -55,6 +55,9 @@ type Client struct {
mu sync.Mutex
}
+// GettingConfig is defined here to satisfy the server.Callbacks interface
+// It is called when internally we are getting a config
+// We go to the GettingConfig state
func (c *Client) GettingConfig() error {
if c.FSM.InState(StateGettingConfig) {
return nil
@@ -63,6 +66,9 @@ func (c *Client) GettingConfig() error {
return err
}
+// InvalidProfile is defined here to satisfy the server.Callbacks interface
+// It is called when a profile is invalid
+// Here we call the AskProfile transition
func (c *Client) InvalidProfile(ctx context.Context, srv *server.Server) (string, error) {
// TODO: should this have profiles as a parameter
ck := cookie.NewWithContext(ctx)
@@ -157,6 +163,8 @@ func New(name string, version string, directory string, stateCallback func(FSMSt
return c, nil
}
+// TriggerAuth is called when authorization is triggered
+// This function satisfies the server.Callbacks interface
func (c *Client) TriggerAuth(ctx context.Context, url string, wait bool) (string, error) {
// Get a reply from the client
if wait {
@@ -185,6 +193,8 @@ func (c *Client) TriggerAuth(ctx context.Context, url string, wait bool) (string
return "", nil
}
+// AuthDone is called when authorization is done
+// This is defined to satisfy the server.Callbacks interface
func (c *Client) AuthDone(id string, t srvtypes.Type) {
srv, err := c.Servers.GetServer(id, t)
if err == nil {
@@ -198,6 +208,9 @@ func (c *Client) AuthDone(id string, t srvtypes.Type) {
}
}
+// TokensUpdated is called when tokens are updated
+// It updates the cache map and the client tokens
+// This is defined to satisfy the server.Callbacks interface
func (c *Client) TokensUpdated(id string, t srvtypes.Type, tok eduoauth.Token) {
if tok.Access == "" {
return
@@ -219,7 +232,7 @@ func (c *Client) TokensUpdated(id string, t srvtypes.Type, tok eduoauth.Token) {
})
}
-// Registering means updating the FSM to get to the initial state correctly
+// Register means updating the FSM to get to the initial state correctly
func (c *Client) Register() error {
err := c.goTransition(StateMain)
if err != nil {
@@ -289,6 +302,8 @@ func (c *Client) locationCallback(ck *cookie.Cookie, orgID string) error {
return nil
}
+// TrySave tries to save the internal state file
+// If an error occurs it logs it
func (c *Client) TrySave() {
err := c.cfg.Save()
if err != nil {
@@ -375,7 +390,7 @@ func (c *Client) GetConfig(ck *cookie.Cookie, identifier string, _type srvtypes.
if err == nil {
// it could be that we are not in getting config yet if we have just done authorization
c.FSM.GoTransition(StateGettingConfig) //nolint:errcheck
- c.FSM.GoTransition(StateGotConfig) //nolint:errcheck
+ c.FSM.GoTransition(StateGotConfig) //nolint:errcheck
} else if !c.FSM.InState(previousState) {
// go back to the previous state if an error occurred
c.FSM.GoTransition(previousState) //nolint:errcheck
@@ -402,7 +417,7 @@ func (c *Client) GetConfig(ck *cookie.Cookie, identifier string, _type srvtypes.
case srvtypes.TypeSecureInternet:
srv, err = c.Servers.GetSecure(ck.Context(), identifier, c.cfg.Discovery(), tok, startup)
- var cErr *discovery.CountryNotFoundError
+ var cErr *discovery.ErrCountryNotFound
if errors.As(err, &cErr) {
err = c.locationCallback(ck, identifier)
if err == nil {
@@ -431,6 +446,7 @@ func (c *Client) GetConfig(ck *cookie.Cookie, identifier string, _type srvtypes.
return cfg, nil
}
+// RemoveServer removes a server
func (c *Client) RemoveServer(identifier string, _type srvtypes.Type) (err error) {
identifier, err = c.convertIdentifier(identifier, _type)
if err != nil {
@@ -443,6 +459,7 @@ func (c *Client) RemoveServer(identifier string, _type srvtypes.Type) (err error
return nil
}
+// CurrentServer gets the current server that is configured
func (c *Client) CurrentServer() (*srvtypes.Current, error) {
curr, err := c.Servers.PublicCurrent(c.cfg.Discovery())
if err != nil {
@@ -451,6 +468,7 @@ func (c *Client) CurrentServer() (*srvtypes.Current, error) {
return curr, nil
}
+// SetProfileID set the profile ID `pID` for the current server
func (c *Client) SetProfileID(pID string) error {
srv, err := c.Servers.CurrentServer()
if err != nil {
@@ -481,12 +499,13 @@ func (c *Client) retrieveTokens(sid string, t srvtypes.Type) (*eduoauth.Token, e
}, nil
}
+// Cleanup cleans up the VPN connection by sending a /disconnect
func (c *Client) Cleanup(ck *cookie.Cookie) error {
srv, err := c.Servers.CurrentServer()
if err != nil {
return i18nerr.Wrap(err, "The current server was not found when cleaning up the connection")
}
- tok, err := c.retrieveTokens(srv.T.ID, srv.T.T)
+ tok, err := c.retrieveTokens(srv.Key.ID, srv.Key.T)
if err != nil {
return i18nerr.Wrap(err, "No OAuth tokens were found when cleaning up the connection")
}
@@ -501,6 +520,8 @@ func (c *Client) Cleanup(ck *cookie.Cookie) error {
return nil
}
+// SetSecureLocation sets a secure internet location for
+// organization ID `orgID` with country code `countryCode`
func (c *Client) SetSecureLocation(orgID string, countryCode string) error {
// not supported with Let's Connect! & govVPN
if !c.hasDiscovery() {
@@ -514,6 +535,8 @@ func (c *Client) SetSecureLocation(orgID string, countryCode string) error {
return nil
}
+// RenewSession is called when the user clicks on the renew session button
+// It re-authorized the server by getting a server without passing tokens
func (c *Client) RenewSession(ck *cookie.Cookie) error {
// getting the current serving with nil tokens means re-authorize
srv, err := c.Servers.CurrentServer()
@@ -529,6 +552,7 @@ func (c *Client) RenewSession(ck *cookie.Cookie) error {
return nil
}
+// StartFailover starts the failover procedure
func (c *Client) StartFailover(ck *cookie.Cookie, gateway string, mtu int, readRxBytes func() (int64, error)) (bool, error) {
f := failover.New(readRxBytes)
@@ -540,6 +564,7 @@ func (c *Client) StartFailover(ck *cookie.Cookie, gateway string, mtu int, readR
return d, nil
}
+// ServerList gets the list of servers
func (c *Client) ServerList() (*srvtypes.List, error) {
g := c.cfg.V2.PublicList(c.cfg.Discovery())
return g, nil
diff --git a/client/client_test.go b/client/client_test.go
index 1d4bf44..a221c93 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -370,7 +370,7 @@ func TestInvalidClientID(t *testing.T) {
k,
"0.1.0-test",
dir,
- func(old FSMStateID, new FSMStateID, data interface{}) bool {
+ func(_ FSMStateID, _ FSMStateID, _ interface{}) bool {
return true
},
false,
diff --git a/client/fsm.go b/client/fsm.go
index 42c0029..175b832 100644
--- a/client/fsm.go
+++ b/client/fsm.go
@@ -9,9 +9,13 @@ import (
)
type (
- FSMStateID = fsm.StateID
- FSMStates = fsm.States
- FSMState = fsm.State
+ // FSMStateID is an alias to the fsm state ID type
+ FSMStateID = fsm.StateID
+ // FSMStates is an alias to the fsm states type
+ FSMStates = fsm.States
+ // FSMState is an alias to the fsm state type
+ FSMState = fsm.State
+ // FSMTransition is an alias to the fsm transition type
FSMTransition = fsm.Transition
)
@@ -53,6 +57,7 @@ const (
StateDisconnected
)
+// GetStateName gets the State name for state `s`
func GetStateName(s FSMStateID) string {
switch s {
case StateDeregistered:
@@ -166,6 +171,7 @@ func newFSM(
return returnedFSM
}
+// SetState sets the state for the client FSM to `state`
func (c *Client) SetState(state FSMStateID) error {
c.mu.Lock()
defer c.mu.Unlock()
@@ -182,6 +188,7 @@ func (c *Client) SetState(state FSMStateID) error {
return nil
}
+// InState returns whether or not the client is in state `state`
func (c *Client) InState(state FSMStateID) bool {
c.mu.Lock()
defer c.mu.Unlock()
diff --git a/client/proxy.go b/client/proxy.go
index 0e78792..4165c0f 100644
--- a/client/proxy.go
+++ b/client/proxy.go
@@ -7,17 +7,21 @@ import (
"github.com/eduvpn/eduvpn-common/types/cookie"
)
+// ProxyLogger is defined here such that we can update the proxyguard logger
type ProxyLogger struct{}
+// Logf logs a message with parameters
func (pl *ProxyLogger) Logf(msg string, params ...interface{}) {
log.Logger.Debugf(msg, params...)
}
+// Log logs a message
func (pl *ProxyLogger) Log(msg string) {
log.Logger.Debugf("%s", msg)
}
func (c *Client) StartProxyguard(ck *cookie.Cookie, listen string, tcpsp int, peer string) error {
+// StartProxyguard starts proxyguard for proxied WireGuard connections
var err error
proxyguard.UpdateLogger(&ProxyLogger{})
err = proxyguard.Client(ck.Context(), listen, tcpsp, peer, -1)
diff --git a/client/token.go b/client/token.go
index d62308b..03ec1d6 100644
--- a/client/token.go
+++ b/client/token.go
@@ -10,12 +10,17 @@ import (
type cacheMap map[string]eduoauth.Token
+// TokenCacher is a structure that caches tokens for each type of server
type TokenCacher struct {
+ // InstituteAccess is the cached map for institute access servers
InstituteAccess cacheMap
- CustomServer cacheMap
- SecureInternet *eduoauth.Token
+ // CustomServer is the cached map for custom server
+ CustomServer cacheMap
+ // SecureInternet is the cached map for the secure internet server
+ SecureInternet *eduoauth.Token
}
+// Get gets tokens from the cache map
func (c *cacheMap) Get(id string) (*eduoauth.Token, error) {
if c == nil || len(*c) == 0 {
return nil, errors.New("no cache map available")
@@ -26,6 +31,7 @@ func (c *cacheMap) Get(id string) (*eduoauth.Token, error) {
return nil, fmt.Errorf("identifier: '%s' does not exist in token cache map", id)
}
+// Get gets tokens using a server id and type from the cacher
func (tc *TokenCacher) Get(id string, t srvtypes.Type) (*eduoauth.Token, error) {
switch t {
case srvtypes.TypeCustom:
@@ -41,6 +47,7 @@ func (tc *TokenCacher) Get(id string, t srvtypes.Type) (*eduoauth.Token, error)
return nil, fmt.Errorf("invalid type for token cacher get: %d", t)
}
+// Set updates the cache for the server id `id` with tokens `t`
func (c *cacheMap) Set(id string, t eduoauth.Token) {
if c == nil || len(*c) == 0 {
*c = make(cacheMap)
@@ -48,6 +55,7 @@ func (c *cacheMap) Set(id string, t eduoauth.Token) {
(*c)[id] = t
}
+// Set updates the top-level cacher for a specific server type
func (tc *TokenCacher) Set(id string, t srvtypes.Type, tok eduoauth.Token) error {
switch t {
case srvtypes.TypeCustom:
diff --git a/cmd/cli/main.go b/cmd/cli/main.go
index 8696813..f769044 100644
--- a/cmd/cli/main.go
+++ b/cmd/cli/main.go
@@ -1,3 +1,4 @@
+// Package main implements an example CLI client
package main
import (
diff --git a/exports/exports.go b/exports/exports.go
index ea4d4bd..4e08e95 100644
--- a/exports/exports.go
+++ b/exports/exports.go
@@ -26,7 +26,7 @@ typedef void (*TokenSetter)(const char* server_id, int server_type, const char*
static long long int get_read_rx_bytes(ReadRxBytes read)
{
- return read();
+ return read();
}
static int call_callback(StateCB callback, int oldstate, int newstate, void* data)
{
@@ -34,11 +34,12 @@ static int call_callback(StateCB callback, int oldstate, int newstate, void* dat
}
static void call_token_getter(TokenGetter getter, const char* server_id, int server_type, char* out, size_t len)
{
- getter(server_id, server_type, out, len);
+ getter(server_id, server_type, out, len);
}
static void call_token_setter(TokenSetter setter, const char* server_id, int server_type, const char* tokens)
{
- setter(server_id, server_type, tokens);
+ setter(server_id, server_type, tokens);
+}
}
*/
import "C"
@@ -58,6 +59,7 @@ import (
srvtypes "github.com/eduvpn/eduvpn-common/types/server"
)
+// VPNState is the current state of the library
var VPNState *client.Client
func getCError(err error) *C.char {
@@ -884,10 +886,10 @@ func StartFailover(c C.uintptr_t, gateway *C.char, mtu C.int, readRxBytes C.Read
// This proxies WireGuard UDP connections over TCP.
// These input variables can be gotten from the configuration that is retrieved using the `proxy` JSON key
//
-// - `c` is the cookie
-// - `listen` is the ip:port of the local udp connection, this is what is set to the WireGuard endpoint
-// - `tcpsp` is the TCP source port
-// - `peer` is the ip:port of the remote server
+// - `c` is the cookie
+// - `listen` is the ip:port of the local udp connection, this is what is set to the WireGuard endpoint
+// - `tcpsp` is the TCP source port
+// - `peer` is the ip:port of the remote server
//
// If the proxy cannot be started it returns an error
//
@@ -1059,8 +1061,8 @@ func SetTokenHandler(getter C.TokenGetter, setter C.TokenSetter) *C.char {
//
// - Send a reply to a state transition (ASK_PROFILE and ASK_LOCATION)
//
-// Functions that take a cookie have it as the first argument
-
+// # Functions that take a cookie have it as the first argument
+//
// Example Input: ```CookieNew()```
//
// Example Output: ```5```
diff --git a/i18nerr/i18nerr.go b/i18nerr/i18nerr.go
index 2dea504..553a7d5 100644
--- a/i18nerr/i18nerr.go
+++ b/i18nerr/i18nerr.go
@@ -1,4 +1,4 @@
-// package i18nerr implements errors with internationalization using gotext
+// Package i18nerr implements errors with internationalization using gotext
package i18nerr
import (
@@ -138,7 +138,7 @@ func Wrapf(err error, key message.Reference, args ...interface{}) *Error {
return &Error{key: key, args: args, wrapped: &Error{key: t, Misc: misc}, Misc: misc}
}
-// NewInternalf creates an internal localised error from a display string
+// NewInternal creates an internal localised error from a display string
func NewInternal(disp string) *Error {
return Wrap(errors.New(disp), "An internal error occurred")
}
diff --git a/internal/api/api.go b/internal/api/api.go
index a9ea0c0..2268357 100644
--- a/internal/api/api.go
+++ b/internal/api/api.go
@@ -1,3 +1,4 @@
+// Package api implements version 3 of the eduVPN api: https://docs.eduvpn.org/server/v3/api.html
package api
import (
@@ -21,12 +22,18 @@ import (
"github.com/eduvpn/eduvpn-common/types/server"
)
+// Callbacks is the API callback interface
+// It is used to trigger authorization and forward token updates
type Callbacks interface {
+ // TriggerAuth is called when authorization should be triggered
TriggerAuth(context.Context, string, bool) (string, error)
+ // AuthDone is called when authorization has just completed
AuthDone(string, server.Type)
+ // TokensUpdates is called when tokens are updated
TokensUpdated(string, server.Type, eduoauth.Token)
}
+// ServerData is the data for a server that is passed to the API struct
type ServerData struct {
// ID is the identifier for the server
ID string
@@ -44,6 +51,7 @@ type ServerData struct {
DisableAuthorize bool
}
+// API is the top-level struct that each method is defined on
type API struct {
cb Callbacks
// oauth is the oauth object
@@ -91,6 +99,7 @@ func NewAPI(ctx context.Context, clientID string, sd ServerData, cb Callbacks, t
return api, nil
}
+// ErrAuthorizeDisabled is returned when authorization is disabled but is needed to complete
var ErrAuthorizeDisabled = errors.New("cannot authorize as re-authorization is disabled")
func (a *API) authorize(ctx context.Context) (err error) {
@@ -168,11 +177,14 @@ func (a *API) authorizedRetry(ctx context.Context, method string, endpoint strin
return h, body, err
}
+// Disconnect disconnects a client from the server by sending a /disconnect API call
+// This cleans up resources such as WireGuard IP allocation
func (a *API) Disconnect(ctx context.Context) error {
_, _, err := a.authorized(ctx, http.MethodPost, "/disconnect", &httpw.OptionalParams{Timeout: 5 * time.Second})
return err
}
+// Info does the /info API call
func (a *API) Info(ctx context.Context) (*profiles.Info, error) {
_, body, err := a.authorizedRetry(ctx, http.MethodGet, "/info", nil)
if err != nil {
@@ -185,16 +197,16 @@ func (a *API) Info(ctx context.Context) (*profiles.Info, error) {
return &p, nil
}
-type Proxy struct {
- Listen string
- Peer string
-}
-
+// ConnectData is the data that is returned when the /connect call completes without error
type ConnectData struct {
+ // Configuration is the VPN configuration
Configuration string
- Protocol protocol.Protocol
- Expires time.Time
- Proxy *wireguard.Proxy
+ // Protocol tells us what protocol it is, OpenVPN or WireGuard (proxied or not)
+ Protocol protocol.Protocol
+ // Expires tells us when this configuration expires
+ Expires time.Time
+ // Proxy is filled when WireGuard is proxied
+ Proxy *wireguard.Proxy
}
// see https://github.com/eduvpn/documentation/blob/v3/API.md#request-1
@@ -345,12 +357,16 @@ func refreshEndpoints(ctx context.Context, sd ServerData) (*endpoints.List, *end
return &ep.API.V3, &epauth.API.V3, err
}
+// OAuthLogger is defined here to update the internal logger
+// for the eduoauth library
type OAuthLogger struct{}
+// Logf logs a message with parameters
func (ol *OAuthLogger) Logf(msg string, params ...interface{}) {
log.Logger.Debugf(msg, params...)
}
+// Log logs a message
func (ol *OAuthLogger) Log(msg string) {
log.Logger.Debugf("%s", msg)
}
diff --git a/internal/api/endpoints/endpoints.go b/internal/api/endpoints/endpoints.go
index 11e244b..c98d2c7 100644
--- a/internal/api/endpoints/endpoints.go
+++ b/internal/api/endpoints/endpoints.go
@@ -1,3 +1,5 @@
+// Package endpoints defines a wrapper around the various
+// endpoints returned by an eduVPN server in well-known
package endpoints
import (
@@ -5,21 +7,30 @@ import (
"net/url"
)
+// List is the list of endpoints as returned by the eduVPN server
type List struct {
- API string `json:"api_endpoint"`
+ // API is the API endpoint which we use for calls such as /info, /connect, ...
+ API string `json:"api_endpoint"`
+ // Authorization is the authorization endpoint for OAuth
Authorization string `json:"authorization_endpoint"`
- Token string `json:"token_endpoint"`
+ // Token is the token endpoint for OAuth
+ Token string `json:"token_endpoint"`
}
+// Versions is the endpoints separated by API version
type Versions struct {
+ // V2 is the legacy V2 API, this is not used
V2 List `json:"http://eduvpn.org/api#2"`
+ // V3 is the newest API, which we use
V3 List `json:"http://eduvpn.org/api#3"`
}
// Endpoints defines the json format for /.well-known/vpn-user-portal".
type Endpoints struct {
+ // API defines the API endpoints, split by version
API Versions `json:"api"`
- V string `json:"v"`
+ // V is the version string for the server
+ V string `json:"v"`
}
// Validate validates the endpoints by parsing them and checking the scheme is HTTP
diff --git a/internal/api/profiles/profiles.go b/internal/api/profiles/profiles.go
index 111a835..d31bbcc 100644
--- a/internal/api/profiles/profiles.go
+++ b/internal/api/profiles/profiles.go
@@ -1,3 +1,5 @@
+// Package profiles defines a wrapper around the various profiles
+// returned by the /info endpoint
package profiles
import (
@@ -5,27 +7,43 @@ import (
"github.com/eduvpn/eduvpn-common/types/server"
)
+// Profile is the information for a profile
type Profile struct {
- ID string `json:"profile_id"`
- DisplayName string `json:"display_name"`
- VPNProtoList []string `json:"vpn_proto_list"`
+ // ID is the identifier of the profile
+ // Used to select a profile
+ ID string `json:"profile_id"`
+ // DisplayName defines the UI friendly name for the profile
+ DisplayName string `json:"display_name"`
+ // VPNProtoList defines the list of VPN protocols
+ // E.g. wireguard, openvpn
+ VPNProtoList []string `json:"vpn_proto_list"`
+ // VPNProtoTransportList defines the list of VPN protocols including their transport values
+ // E.g. wireguard+udp, openvpn+tcp
VPNProtoTransportList []string `json:"vpn_proto_transport_list"`
- DefaultGateway bool `json:"default_gateway"`
- DNSSearchDomains []string `json:"dns_search_domain_list"`
+ // DefaultGateway specifies whether or not this profile is a default gateway profile
+ DefaultGateway bool `json:"default_gateway"`
+ // DNSSearchDomains specifies the list of dns search domains
+ // This is provided for a Linux client issue
+ // See: https://github.com/eduvpn/python-eduvpn-client/issues/550
+ DNSSearchDomains []string `json:"dns_search_domain_list"`
}
+// ListInfo is the struct that has the profile list
type ListInfo struct {
ProfileList []Profile `json:"profile_list"`
}
+// Info is the top-level struct for the info endpoint
type Info struct {
Info ListInfo `json:"info"`
}
+// Len returns the length of the profile list
func (i Info) Len() int {
return len(i.Info.ProfileList)
}
+// Get returns a profile with id `id`, it returns nil if it is not found
func (i Info) Get(id string) *Profile {
for _, p := range i.Info.ProfileList {
if p.ID == id {
@@ -35,6 +53,8 @@ func (i Info) Get(id string) *Profile {
return nil
}
+// MustIndex gets a profile by index
+// This index must be in the bounds
func (i Info) MustIndex(n int) Profile {
return i.Info.ProfileList[n]
}
@@ -48,6 +68,11 @@ func hasProtocol(protos []string, proto protocol.Protocol) bool {
return false
}
+// ShouldFailover returns whether or not this VPN profile should start a failover procedure
+// This is true when the profile supports a TCP connection
+// If we cannot determine whether it supports a TCP connection
+// (because the server doesn't provide the VPN transport list function yet),
+// we will just check if it supports OpenVPN
func (p *Profile) ShouldFailover() bool {
// old servers don't support it, only failover in case OpenVPN is supported
if len(p.VPNProtoTransportList) == 0 {
@@ -65,14 +90,17 @@ func (p *Profile) ShouldFailover() bool {
return false
}
+// HasOpenVPN returns whether or not the profile has OpenVPN support
func (p *Profile) HasOpenVPN() bool {
return hasProtocol(p.VPNProtoList, protocol.OpenVPN)
}
+// HasWireGuard returns whether or not the profile has WireGuard support
func (p *Profile) HasWireGuard() bool {
return hasProtocol(p.VPNProtoList, protocol.WireGuard)
}
+// FilterWireGuard gets a profile list but without WireGuard profiles
func (i Info) FilterWireGuard() *Info {
var ret []Profile
for _, p := range i.Info.ProfileList {
@@ -87,6 +115,7 @@ func (i Info) FilterWireGuard() *Info {
}
}
+// Public gets the server list as a structure that we return to clients
func (i Info) Public() server.Profiles {
m := make(map[string]server.Profile)
for _, p := range i.Info.ProfileList {
diff --git a/internal/config/config.go b/internal/config/config.go
index 59d47e0..ed424f8 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -16,19 +16,23 @@ import (
const stateFile = "state.json"
+// Config represents the config state file
type Config struct {
directory string
- V2 *v2.V2
+ // V2 indicates we are version 2
+ V2 *v2.V2
}
func (c *Config) filename() string {
return path.Join(c.directory, stateFile)
}
+// Discovery gets the discovery list from the state file
func (c *Config) Discovery() *discovery.Discovery {
return &c.V2.Discovery
}
+// Save saves the state file to disk
func (c *Config) Save() error {
if err := util.EnsureDirectory(c.directory); err != nil {
return err
@@ -45,6 +49,7 @@ func (c *Config) Save() error {
return nil
}
+// Load loads the state file from disk
func (c *Config) Load() error {
bts, err := os.ReadFile(c.filename())
if err != nil {
@@ -64,11 +69,16 @@ func (c *Config) Load() error {
return nil
}
+// Versioned is the final top-level state file that is written to disk
type Versioned struct {
+ // V1 is the version 1 state file that is no longer used but converted from
V1 *v1.V1 `json:"v1,omitempty"`
+ // V2 is the version 2 state file
V2 *v2.V2 `json:"v2,omitempty"`
}
+// NewFromDirectory creates a new config struct from a directory
+// It does this by loading the JSON file from disk
func NewFromDirectory(dir string) *Config {
cfg := Config{
directory: dir,
diff --git a/internal/config/v1/v1.go b/internal/config/v1/v1.go
index 1e374b1..1d96d13 100644
--- a/internal/config/v1/v1.go
+++ b/internal/config/v1/v1.go
@@ -12,49 +12,78 @@ import (
"github.com/eduvpn/eduvpn-common/types/server"
)
+// Profiles is the list of profiles
type Profiles struct {
profiles.Info
Current string `json:"current_profile"`
}
+// Base is the base type of a server
type Base struct {
- BaseURL string `json:"base_url"`
- Profiles Profiles `json:"profiles"`
- StartTime time.Time `json:"start_time"`
+ // BaseURL is the base_url from discovery
+ BaseURL string `json:"base_url"`
+ // profiles is the last of profile
+ Profiles Profiles `json:"profiles"`
+ // StartTime is the time when we started the connection
+ StartTime time.Time `json:"start_time"`
+ // StartTimeOAuth is the time when we last started OAuth
StartTimeOAuth time.Time `json:"start_time_oauth"`
- ExpireTime time.Time `json:"expire_time"`
+ // ExpireTime is the time when the connection expires
+ ExpireTime time.Time `json:"expire_time"`
}
+// InstituteServer is the struct that represents an institute access server
type InstituteServer struct {
- Base Base `json:"base"`
+ // Base is the base of the server
+ Base Base `json:"base"`
+ // Profiles are the list of profiles
Profiles Profiles `json:"profiles"`
}
+// InstituteServers is a list of institute access servers
type InstituteServers struct {
- Map map[string]InstituteServer `json:"map"`
- CurrentURL string `json:"current_url"`
+ // Map is the map from base url to an institute access server
+ Map map[string]InstituteServer `json:"map"`
+ // CurrentURL is the URL of the currently configured server
+ CurrentURL string `json:"current_url"`
}
type (
- CustomServer = InstituteServer
+ // CustomServer is an alias to InstituteServer
+ CustomServer = InstituteServer
+ // CustomServers is an alias to InstituteServers
CustomServers = InstituteServers
)
+// SecureInternetHome represents a secure internet home server
type SecureInternetHome struct {
- BaseMap map[string]*Base `json:"base_map"`
- DisplayName map[string]string `json:"display_name"`
- HomeOrganizationID string `json:"home_organization_id"`
- CurrentLocation string `json:"current_location"`
+ // BaseMap is the map from country code to a server base
+ BaseMap map[string]*Base `json:"base_map"`
+ // DisplayName is the map from language code to UI name
+ DisplayName map[string]string `json:"display_name"`
+ // HomeOrganizationID is the identifier of the home organization
+ HomeOrganizationID string `json:"home_organization_id"`
+ // CurrentLocation is the country code of the currently configured server
+ CurrentLocation string `json:"current_location"`
}
+// Servers represents the list of servers
type Servers struct {
- Custom CustomServers `json:"custom_servers"`
- Institute InstituteServers `json:"institute_servers"`
+ // Custom are the "custom" servers; the servers that are added by the user
+ Custom CustomServers `json:"custom_servers"`
+ // Institute are the institute access servers configured from discovery
+ Institute InstituteServers `json:"institute_servers"`
+ // SecureInternetHome is the secure internet home server
+ // Also obtained through discovery
SecureInternetHome SecureInternetHome `json:"secure_internet_home"`
- IsType server.Type `json:"is_secure_internet"`
+ // IsType represents which server type was last configured
+ IsType server.Type `json:"is_secure_internet"`
}
+// V1 is the top-level struct for the first version of the state file
type V1 struct {
+ // Discovery is the list of discovery servers
Discovery discovery.Discovery `json:"discovery"`
- Servers Servers `json:"servers"`
+ // Servers is the list of servers in the app
+ Servers Servers `json:"servers"`
}
diff --git a/internal/config/v2/convert.go b/internal/config/v2/convert.go
index 0212749..21f39a9 100644
--- a/internal/config/v2/convert.go
+++ b/internal/config/v2/convert.go
@@ -15,11 +15,11 @@ func v1AuthTime(st time.Time, ost time.Time) time.Time {
return ost
}
-func convertV1Server(list v1.InstituteServers, iscurrent bool, t server.Type) (map[ServerType]*Server, *ServerType) {
- ret := make(map[ServerType]*Server)
- var lc *ServerType
+func convertV1Server(list v1.InstituteServers, iscurrent bool, t server.Type) (map[ServerKey]*Server, *ServerKey) {
+ ret := make(map[ServerKey]*Server)
+ var lc *ServerKey
for k, v := range list.Map {
- key := ServerType{
+ key := ServerKey{
T: t,
ID: k,
}
@@ -37,10 +37,11 @@ func convertV1Server(list v1.InstituteServers, iscurrent bool, t server.Type) (m
return ret, lc
}
+// FromV1 converts a version 1 state struct into a v2 one
func FromV1(ver1 *v1.V1) *V2 {
gsrvs := ver1.Servers
- var lc *ServerType
+ var lc *ServerKey
cust, glc := convertV1Server(gsrvs.Custom, gsrvs.IsType == server.TypeCustom, server.TypeCustom)
if lc == nil {
lc = glc
@@ -64,7 +65,7 @@ func FromV1(ver1 *v1.V1) *V2 {
}
v, ok := sec.BaseMap[sec.CurrentLocation]
if v != nil && ok {
- t := ServerType{
+ t := ServerKey{
T: server.TypeSecureInternet,
ID: sec.HomeOrganizationID,
}
diff --git a/internal/config/v2/v2.go b/internal/config/v2/v2.go
index 9608d54..51f7a5f 100644
--- a/internal/config/v2/v2.go
+++ b/internal/config/v2/v2.go
@@ -1,3 +1,4 @@
+// Package v2 implements version 2 of the state file
package v2
import (
@@ -10,41 +11,52 @@ import (
"github.com/eduvpn/eduvpn-common/types/server"
)
+// Server is the struct for each server
type Server struct {
- Profiles server.Profiles `json:"profiles"`
- LastAuthorizeTime time.Time `json:"last_authorize_time,omitempty"`
- ExpireTime time.Time `json:"expire_time,omitempty"`
+ // Profiles are the list of profiles
+ Profiles server.Profiles `json:"profiles"`
+ // LastAuthorizeTime is the time we last authorized
+ // This is used for determining when to show e.g. the renew button
+ LastAuthorizeTime time.Time `json:"last_authorize_time,omitempty"`
+ // ExpireTime is the time at which the VPN expires
+ ExpireTime time.Time `json:"expire_time,omitempty"`
- // In case of secure internet:
+ // CountryCode is the country code for the server in case of secure internet
+ // Otherwise it is an empty string
CountryCode string `json:"country_code"`
}
-type ServerType struct {
- T server.Type
+// ServerKey is the key type of the server map
+type ServerKey struct {
+ // T is the type of server, e.g. secure internet
+ T server.Type
+ // ID is the identifier for the server
ID string
}
const keyFormat = "%d,%s"
-func newServerType(key string) (*ServerType, error) {
+func newServerType(key string) (*ServerKey, error) {
var t server.Type
var id string
if _, err := fmt.Sscanf(key, keyFormat, &t, &id); err != nil {
return nil, err
}
- return &ServerType{
+ return &ServerKey{
T: t,
ID: id,
}, nil
}
-func (st ServerType) MarshalText() ([]byte, error) {
+// MarshalText convers the server key into one that can be used in a map
+func (st ServerKey) MarshalText() ([]byte, error) {
k := fmt.Sprintf(keyFormat, st.T, st.ID)
return []byte(k), nil
}
-func (st *ServerType) UnmarshalText(text []byte) error {
+// UnmarshalText converts the marshaled key into a ServerType struct
+func (st *ServerKey) UnmarshalText(text []byte) error {
k := string(text)
g, err := newServerType(k)
if err != nil {
@@ -54,14 +66,21 @@ func (st *ServerType) UnmarshalText(text []byte) error {
return nil
}
+// V2 is the top-level struct for the state file
type V2 struct {
- List map[ServerType]*Server `json:"server_list,omitempty"`
- LastChosen *ServerType `json:"last_chosen_id,omitempty"`
- Discovery discovery.Discovery `json:"discovery"`
+ // List is the list of servers
+ List map[ServerKey]*Server `json:"server_list,omitempty"`
+ // LastChosen represents the key of the last chosen server
+ // A server is chosen if we got a config for it
+ LastChosen *ServerKey `json:"last_chosen_id,omitempty"`
+ // Discovery is the cached list of discovery JSON
+ Discovery discovery.Discovery `json:"discovery"`
}
+// RemoveServer removes a server with id `id` and type `t` from the V2 struct
+// It returns an error if no such server exists
func (cfg *V2) RemoveServer(id string, t server.Type) error {
- k := ServerType{
+ k := ServerKey{
ID: id,
T: t,
}
@@ -78,22 +97,26 @@ func (cfg *V2) RemoveServer(id string, t server.Type) error {
return errors.New("server does not exist")
}
-func (cfg *V2) getServerWithKey(k ServerType) (*Server, error) {
+func (cfg *V2) getServerWithKey(k ServerKey) (*Server, error) {
if v, ok := cfg.List[k]; ok {
return v, nil
}
return nil, errors.New("server does not exist")
}
+// GetServer gets a server with id `id` and type `t`
+// If the server doesn't exist it returns nil and an error
func (cfg *V2) GetServer(id string, t server.Type) (*Server, error) {
- k := ServerType{
+ k := ServerKey{
ID: id,
T: t,
}
return cfg.getServerWithKey(k)
}
-func (cfg *V2) CurrentServer() (*Server, *ServerType, error) {
+// CurrentServer gets the last chosen server
+// It returns the server, the server type and an error if it doesn't exist
+func (cfg *V2) CurrentServer() (*Server, *ServerKey, error) {
if cfg.LastChosen == nil {
return nil, nil, errors.New("no server chosen before")
}
@@ -104,6 +127,8 @@ func (cfg *V2) CurrentServer() (*Server, *ServerType, error) {
return srv, cfg.LastChosen, nil
}
+// HasSecureInternet returns true whether or not the state file
+// has a secure internet server in it
func (cfg *V2) HasSecureInternet() bool {
for k := range cfg.List {
if k.T == server.TypeSecureInternet {
@@ -113,21 +138,24 @@ func (cfg *V2) HasSecureInternet() bool {
return false
}
+// AddServer adds a server with id `id`, type `t` and server `srv`
func (cfg *V2) AddServer(id string, t server.Type, srv Server) error {
if cfg.HasSecureInternet() && t == server.TypeSecureInternet {
return errors.New("a secure internet server already exists, remove the other secure internet server first")
}
- k := ServerType{
+ k := ServerKey{
ID: id,
T: t,
}
if cfg.List == nil {
- cfg.List = make(map[ServerType]*Server)
+ cfg.List = make(map[ServerKey]*Server)
}
cfg.List[k] = &srv
return nil
}
+// PublicCurrent gets the current server as a type that should be returned to the client
+// It returns this server or nil and an error if it doesn't exist
func (cfg *V2) PublicCurrent(disco *discovery.Discovery) (*server.Current, error) {
curr, _, err := cfg.CurrentServer()
if err != nil {
@@ -207,6 +235,7 @@ func convertSecure(orgID string, countryCode string, disco *discovery.Discovery)
}, nil
}
+// PublicList gets all the servers in a format that is returned to the client
func (cfg *V2) PublicList(disco *discovery.Discovery) *server.List {
ret := &server.List{}
// TODO: profile information?
diff --git a/internal/config/v2/v2_test.go b/internal/config/v2/v2_test.go
index 5a4c2ea..ce8de01 100644
--- a/internal/config/v2/v2_test.go
+++ b/internal/config/v2/v2_test.go
@@ -36,7 +36,7 @@ func TestLoad(t *testing.T) {
}
`,
want: &V2{
- List: map[ServerType]*Server{
+ List: map[ServerKey]*Server{
{ID: "a", T: server.TypeInstituteAccess}: {
Profiles: server.Profiles{
Map: map[string]server.Profile{
@@ -103,7 +103,7 @@ func TestLoad(t *testing.T) {
}
`,
want: &V2{
- List: map[ServerType]*Server{
+ List: map[ServerKey]*Server{
{ID: "a", T: server.TypeInstituteAccess}: {
Profiles: server.Profiles{
Map: map[string]server.Profile{
diff --git a/internal/discovery/discovery.go b/internal/discovery/discovery.go
index 88a37d9..6db9425 100644
--- a/internal/discovery/discovery.go
+++ b/internal/discovery/discovery.go
@@ -27,6 +27,7 @@ type Discovery struct {
ServerList discotypes.Servers `json:"servers"`
}
+// DiscoURL is the URL used for fetching the discovery files and signatures
var DiscoURL = "https://disco.eduvpn.org/v2/"
// file is a helper function that gets a disco JSON and fills the structure with it
@@ -123,11 +124,12 @@ func (discovery *Discovery) ServerByURL(
return nil, fmt.Errorf("no server of type '%s' at URL '%s'", srvType, baseURL)
}
-type CountryNotFoundError struct {
+// ErrCountryNotFound is used when the secure internet country cannot be found
+type ErrCountryNotFound struct {
CountryCode string
}
-func (cnf *CountryNotFoundError) Error() string {
+func (cnf *ErrCountryNotFound) Error() string {
return fmt.Sprintf("no secure internet server with country code: '%s'", cnf.CountryCode)
}
@@ -139,7 +141,7 @@ func (discovery *Discovery) ServerByCountryCode(countryCode string) (*discotypes
return &srv, nil
}
}
- return nil, &CountryNotFoundError{CountryCode: countryCode}
+ return nil, &ErrCountryNotFound{CountryCode: countryCode}
}
// orgByID returns the discovery organization by the organization ID
diff --git a/internal/failover/failover.go b/internal/failover/failover.go
index 97b1da1..bbd1978 100644
--- a/internal/failover/failover.go
+++ b/internal/failover/failover.go
@@ -1,3 +1,5 @@
+// Package failover implements the failover procedure
+// by sending pings and checking if the VPN is up
package failover
import (
diff --git a/internal/failover/monitor.go b/internal/failover/monitor.go
index d9028f2..5d81f22 100644
--- a/internal/failover/monitor.go
+++ b/internal/failover/monitor.go
@@ -20,6 +20,10 @@ type DroppedConMon struct {
readRxBytes func() (int64, error)
}
+// NewDroppedMonitor creates a new failover monitor
+// `pingInterval` is the interval in which to send pings
+// `pDropped` is how many pings we need to send before we deem it is dropped
+// `readRxBytes` is a function that gets the rx bytes from the client
func NewDroppedMonitor(pingInterval time.Duration, pDropped int, readRxBytes func() (int64, error)) *DroppedConMon {
return &DroppedConMon{pInterval: pingInterval, pDropped: pDropped, readRxBytes: readRxBytes}
}
diff --git a/internal/failover/ping.go b/internal/failover/ping.go
index 3b5faa8..59dbcc9 100644
--- a/internal/failover/ping.go
+++ b/internal/failover/ping.go
@@ -13,12 +13,14 @@ import (
// mtuOverhead defines the total MTU overhead for an ICMP ECHO message: 20 bytes IP header + 8 bytes ICMP header
var mtuOverhead = 28
+// Pinger sends pings
type Pinger struct {
listener net.PacketConn
buffer []byte
gateway net.Addr
}
+// Read reads from the ping listener with deadline `deadline`
func (p Pinger) Read(deadline time.Time) error {
// First set the deadline to read
err := p.listener.SetReadDeadline(deadline)
@@ -43,6 +45,7 @@ func (p Pinger) Read(deadline time.Time) error {
}
}
+// Send sends a single ping
func (p Pinger) Send(seq int) error {
errorMessage := fmt.Sprintf("failed sending ping, seq %d", seq)
// Make a new ICMP message
diff --git a/internal/failover/ping_default.go b/internal/failover/ping_default.go
index c490869..11401bb 100644
--- a/internal/failover/ping_default.go
+++ b/internal/failover/ping_default.go
@@ -9,6 +9,7 @@ import (
"golang.org/x/net/icmp"
)
+// NewPinger creates a new pinger with gateway `gateway` and size `size`
func NewPinger(gateway string, size int) (*Pinger, error) {
l, err := icmp.ListenPacket("udp4", "0.0.0.0")
if err != nil {
diff --git a/internal/fsm/fsm.go b/internal/fsm/fsm.go
index f5bebd7..0fe3444 100644
--- a/internal/fsm/fsm.go
+++ b/internal/fsm/fsm.go
@@ -16,14 +16,17 @@ type (
StateIDSlice []StateID
)
+// Len is defined here such that we can sort the slice
func (v StateIDSlice) Len() int {
return len(v)
}
+// Less is defined here such that we can sort the slice
func (v StateIDSlice) Less(i, j int) bool {
return v[i] < v[j]
}
+// Swap is defined here such that we can sort the slice
func (v StateIDSlice) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
@@ -36,9 +39,8 @@ type Transition struct {
Description string
}
-type (
- States map[StateID]State
-)
+// States is the map from state identifier to the state itself
+type States map[StateID]State
// State represents a single node in the graph.
type State struct {
@@ -97,6 +99,8 @@ func (fsm *FSM) InState(check StateID) bool {
return check == fsm.Current
}
+// CheckTransition returns an error whether or not a transition to
+// state `desired` is possible
func (fsm *FSM) CheckTransition(desired StateID) error {
// initial or begin state is fine
// 0 = deregistered
diff --git a/internal/http/http.go b/internal/http/http.go
index ba081fd..09f1953 100644
--- a/internal/http/http.go
+++ b/internal/http/http.go
@@ -146,7 +146,7 @@ type Client struct {
Timeout time.Duration
}
-// Returns a HTTP client with some default settings
+// NewClient returns a HTTP client with some default settings
func NewClient(client *http.Client) *Client {
c := client
if c == nil {
@@ -169,7 +169,7 @@ func (c *Client) PostWithOpts(ctx context.Context, url string, opts *OptionalPar
return c.Do(ctx, http.MethodPost, url, opts)
}
-// MethodWithOpts Do send a HTTP request using a method (e.g. GET, POST), an url and optional parameters
+// Do sends a HTTP request using a method (e.g. GET, POST), an url and optional parameters
// It returns the HTTP headers, the body and an error if there is one.
func (c *Client) Do(ctx context.Context, method string, urlStr string, opts *OptionalParams) (http.Header, []byte, error) {
// Make sure the url contains all the parameters
diff --git a/internal/log/log.go b/internal/log/log.go
index 8d3fbfb..02373c9 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -24,6 +24,7 @@ type FileLogger struct {
// Logger is the global logger instance
var Logger *FileLogger
+// Level is the level of log, e.g. debug
type Level int8
const (
@@ -88,7 +89,7 @@ func (logger *FileLogger) Init(lvl Level, dir string) error {
return nil
}
-// Inheritf logs an error with a message and params using the error level verbosity of the error.
+// Inherit logs an error with a message and params using the error level verbosity of the error.
// The message is always prefixed with the error.
func (logger *FileLogger) Inherit(err error, msg string) {
if err == nil {
diff --git a/internal/server/custom.go b/internal/server/custom.go
index b4b81cb..10e9a28 100644
--- a/internal/server/custom.go
+++ b/internal/server/custom.go
@@ -10,6 +10,10 @@ import (
"github.com/jwijenbergh/eduoauth-go"
)
+// AddCustom adds a custom server to the internal server list
+// `ctx` is the context used for cancellation
+// `id` is the identifier of the server, the base URL
+// `na` specifies whether or not we want to add the server without doing authorization now
func (s *Servers) AddCustom(ctx context.Context, id string, na bool) (*Server, error) {
sd := api.ServerData{
ID: id,
@@ -39,6 +43,11 @@ func (s *Servers) AddCustom(ctx context.Context, id string, na bool) (*Server, e
return &cust, nil
}
+// GetCustom gets a custom server
+// `ctx` is the context for cancellation
+// `id` is the identifier of the server
+// `tok` are the tokens such that we can initialize the API
+// `disableAuth` is set to True when authorization should not be triggered
func (s *Servers) GetCustom(ctx context.Context, id string, tok *eduoauth.Token, disableAuth bool) (*Server, error) {
sd := api.ServerData{
ID: id,
diff --git a/internal/server/institute.go b/internal/server/institute.go
index 881f96d..aa032c7 100644
--- a/internal/server/institute.go
+++ b/internal/server/institute.go
@@ -11,6 +11,11 @@ import (
"github.com/jwijenbergh/eduoauth-go"
)
+// AddInstitute adds an institute access server
+// `ctx` is the context used for cancellation
+// `disco` are the discovery servers
+// `id` is the identifier for the server, the base url
+// `na` is true when authorization should not be triggered
func (s *Servers) AddInstitute(ctx context.Context, disco *discovery.Discovery, id string, na bool) (*Server, error) {
// This is basically done to double check if the server is part of the institute access section of disco
dsrv, err := disco.ServerByURL(id, "institute_access")
@@ -43,6 +48,12 @@ func (s *Servers) AddInstitute(ctx context.Context, disco *discovery.Discovery,
return &inst, nil
}
+// GetInstitute gets an institute access server
+// `ctx` is the context used for cancellation
+// `id` is the identifier for the server, the base url
+// `disco` are the discovery servers
+// `tok` are the tokens such that we do not have to trigger auth
+// `disableAuth` is true when auth should never be triggered
func (s *Servers) GetInstitute(ctx context.Context, id string, disco *discovery.Discovery, tok *eduoauth.Token, disableAuth bool) (*Server, error) {
// This is basically done to double check if the server is part of the institute access section of disco
dsrv, err := disco.ServerByURL(id, "institute_access")
diff --git a/internal/server/secureinternet.go b/internal/server/secureinternet.go
index 19e75a1..0d06a55 100644
--- a/internal/server/secureinternet.go
+++ b/internal/server/secureinternet.go
@@ -13,6 +13,11 @@ import (
"github.com/jwijenbergh/eduoauth-go"
)
+// AddSecure adds a secure internet server
+// `ctx` is the context used for cancellation
+// `disco` are the discovery servers
+// `orgID` is the organiztaion ID
+// `na` specifies whether or not authorization should be triggered when adding
func (s *Servers) AddSecure(ctx context.Context, disco *discovery.Discovery, orgID string, na bool) (*Server, error) {
if s.config.HasSecureInternet() {
return nil, errors.New("a secure internet server already exists")
@@ -54,6 +59,12 @@ func (s *Servers) AddSecure(ctx context.Context, disco *discovery.Discovery, org
return &sec, nil
}
+// GetSecure gets a secure internet server
+// `ctx` is the context used for cancellation
+// `orgID` is the organization ID that identifies the server
+// `disco` are the discovery servers
+// `tok` are the tokens such that the server can be found without triggering auth
+// `disableAuth` is set to true when authorization should not be triggered
func (s *Servers) GetSecure(ctx context.Context, orgID string, disco *discovery.Discovery, tok *eduoauth.Token, disableAuth bool) (*Server, error) {
srv, err := s.config.GetServer(orgID, server.TypeSecureInternet)
if err != nil {
diff --git a/internal/server/server.go b/internal/server/server.go
index bffeb2c..4b960a5 100644
--- a/internal/server/server.go
+++ b/internal/server/server.go
@@ -1,3 +1,4 @@
+// Package server implements functions that have to deal with server interaction
package server
import (
@@ -13,6 +14,7 @@ import (
srvtypes "github.com/eduvpn/eduvpn-common/types/server"
)
+// Server is the struct for a single server
type Server struct {
identifier string
t srvtypes.Type
@@ -20,8 +22,10 @@ type Server struct {
storage *v2.V2
}
+// ErrInvalidProfile is an error that is returned when an invalid profile has been chosen
var ErrInvalidProfile = errors.New("invalid profile")
+// NewServer creates a new server
func (s *Servers) NewServer(identifier string, t srvtypes.Type, api *api.API) Server {
return Server{
identifier: identifier,
@@ -155,6 +159,7 @@ func (s *Server) connect(ctx context.Context, wgSupport bool, pTCP bool) (*srvty
}, nil
}
+// Disconnect sends an API /disconnect to the server
func (s *Server) Disconnect(ctx context.Context) error {
a, err := s.api()
if err != nil {
@@ -170,6 +175,7 @@ func (s *Server) cfgServer() (*v2.Server, error) {
return s.storage.GetServer(s.identifier, s.t)
}
+// SetProfileID sets the profile id `id` for the server
func (s *Server) SetProfileID(id string) error {
cs, err := s.cfgServer()
if err != nil {
@@ -179,6 +185,7 @@ func (s *Server) SetProfileID(id string) error {
return nil
}
+// SetProfileList sets the profile list `prfs` for the server
func (s *Server) SetProfileList(prfs srvtypes.Profiles) error {
cs, err := s.cfgServer()
if err != nil {
@@ -188,6 +195,7 @@ func (s *Server) SetProfileList(prfs srvtypes.Profiles) error {
return nil
}
+// SetExpireTime sets the time `et` when the VPN expires
func (s *Server) SetExpireTime(et time.Time) error {
cs, err := s.cfgServer()
if err != nil {
@@ -197,6 +205,7 @@ func (s *Server) SetExpireTime(et time.Time) error {
return nil
}
+// ProfileID gets the profile ID for the server
func (s *Server) ProfileID() (string, error) {
cs, err := s.cfgServer()
if err != nil {
@@ -205,6 +214,7 @@ func (s *Server) ProfileID() (string, error) {
return cs.Profiles.Current, nil
}
+// SetLocation sets the secure internet location for the server
func (s *Server) SetLocation(loc string) error {
if s.t != srvtypes.TypeSecureInternet {
return errors.New("changing secure internet location is only possible when the server is a secure location")
@@ -217,11 +227,12 @@ func (s *Server) SetLocation(loc string) error {
return nil
}
+// SetCurrent sets the current server in the state file to this one
func (s *Server) SetCurrent() error {
if s.storage == nil {
return errors.New("no storage available")
}
- s.storage.LastChosen = &v2.ServerType{
+ s.storage.LastChosen = &v2.ServerKey{
ID: s.identifier,
T: s.t,
}
diff --git a/internal/server/servers.go b/internal/server/servers.go
index fe2550c..64e64b6 100644
--- a/internal/server/servers.go
+++ b/internal/server/servers.go
@@ -12,23 +12,31 @@ import (
"github.com/jwijenbergh/eduoauth-go"
)
+// Callbacks defines the interface for doing certain callback operations
type Callbacks interface {
+ // api.Callbacks is the API callback interface
api.Callbacks
+ // GettingConfig is called when the config is obtained
GettingConfig() error
+ // InvalidProfile is called when an invalid profile is found
InvalidProfile(context.Context, *Server) (string, error)
}
+// Servers is the main struct that contains information for configuring the servers
type Servers struct {
- clientID string
- cb Callbacks
+ clientID string
+ cb Callbacks
+ // WGSupport defines whether or not wireguard support is enabled
WGSupport bool
config *v2.V2
}
+// Remove removes a server with id `identifier` and type `t`
func (s *Servers) Remove(identifier string, t srvtypes.Type) error {
return s.config.RemoveServer(identifier, t)
}
+// NewServers creates a new servers struct
func NewServers(name string, cb Callbacks, wgSupport bool, cfg *v2.V2) Servers {
return Servers{
clientID: name,
@@ -38,25 +46,31 @@ func NewServers(name string, cb Callbacks, wgSupport bool, cfg *v2.V2) Servers {
}
}
+// CurrentServer contains the information for the current active server
type CurrentServer struct {
+ // it embeds the state file server
*v2.Server
- T v2.ServerType
+ // Key is the server key
+ Key v2.ServerKey
+ // srvs refers to the original servers manager
srvs *Servers
}
+// ServerWithCallbacks gets the current server as a server struct and triggers callbacks as needed
func (cs *CurrentServer) ServerWithCallbacks(ctx context.Context, disco *discovery.Discovery, tokens *eduoauth.Token, disableAuth bool) (*Server, error) {
- switch cs.T.T {
+ switch cs.Key.T {
case srvtypes.TypeInstituteAccess:
- return cs.srvs.GetInstitute(ctx, cs.T.ID, disco, tokens, disableAuth)
+ return cs.srvs.GetInstitute(ctx, cs.Key.ID, disco, tokens, disableAuth)
case srvtypes.TypeSecureInternet:
- return cs.srvs.GetSecure(ctx, cs.T.ID, disco, tokens, disableAuth)
+ return cs.srvs.GetSecure(ctx, cs.Key.ID, disco, tokens, disableAuth)
case srvtypes.TypeCustom:
- return cs.srvs.GetCustom(ctx, cs.T.ID, tokens, disableAuth)
+ return cs.srvs.GetCustom(ctx, cs.Key.ID, tokens, disableAuth)
default:
- return nil, fmt.Errorf("no such server type: %d", cs.T.T)
+ return nil, fmt.Errorf("no such server type: %d", cs.Key.T)
}
}
+// GetServer gets a server from the state file
func (s *Servers) GetServer(id string, t srvtypes.Type) (*v2.Server, error) {
if s.config == nil {
return nil, errors.New("no configuration available")
@@ -64,6 +78,7 @@ func (s *Servers) GetServer(id string, t srvtypes.Type) (*v2.Server, error) {
return s.config.GetServer(id, t)
}
+// CurrentServer gets the current server from the state file and wraps it into a neat type
func (s *Servers) CurrentServer() (*CurrentServer, error) {
curr, k, err := s.config.CurrentServer()
if err != nil {
@@ -71,15 +86,18 @@ func (s *Servers) CurrentServer() (*CurrentServer, error) {
}
return &CurrentServer{
Server: curr,
- T: *k,
+ Key: *k,
srvs: s,
}, nil
}
+// PublicCurrent gets the current server into a type that we can return to the client
func (s *Servers) PublicCurrent(disco *discovery.Discovery) (*srvtypes.Current, error) {
return s.config.PublicCurrent(disco)
}
+// ConnectWithCallbacks handles the /connect flow
+// It calls callbacks as needed
func (s *Servers) ConnectWithCallbacks(ctx context.Context, srv *Server, pTCP bool) (*srvtypes.Configuration, error) {
err := srv.SetCurrent()
if err != nil {
diff --git a/internal/server/time.go b/internal/server/time.go
index 4e54ef6..7369f47 100644
--- a/internal/server/time.go
+++ b/internal/server/time.go
@@ -28,6 +28,7 @@ func RenewButtonTime(st time.Time, et time.Time) int64 {
return t.Unix()
}
+// CountdownTime returns the time when the countdown timer should be shown
func CountdownTime(st time.Time, et time.Time) int64 {
d := et.Sub(st)
@@ -44,6 +45,8 @@ func CountdownTime(st time.Time, et time.Time) int64 {
return t.Unix()
}
+// NotificationTimes returns the list when the app should
+// show a notification when the VPN is (about to) expire(d)
func NotificationTimes(st time.Time, et time.Time) []int64 {
last := []time.Duration{
time.Duration(0),
diff --git a/internal/test/error.go b/internal/test/error.go
index 98fa09b..b2ddd12 100644
--- a/internal/test/error.go
+++ b/internal/test/error.go
@@ -2,6 +2,7 @@ package test
import "testing"
+// AssertError asserts an error by checking if the `Error()` strings are equal
func AssertError(t *testing.T, err error, wantErr string) {
gv := ""
if err != nil {
diff --git a/internal/test/handler.go b/internal/test/handler.go
index 3991c6a..bb5f7a0 100644
--- a/internal/test/handler.go
+++ b/internal/test/handler.go
@@ -11,12 +11,14 @@ type HandlerSet struct {
handler http.Handler
}
+// SetHandler sets the handler to `handler`
func (hs *HandlerSet) SetHandler(handler http.Handler) {
hs.mu.Lock()
hs.handler = handler
hs.mu.Unlock()
}
+// ServeHTTP serves HTTP using the handler
func (hs *HandlerSet) ServeHTTP(w http.ResponseWriter, r *http.Request) {
hs.mu.Lock()
handler := hs.handler
diff --git a/internal/test/server.go b/internal/test/server.go
index 6d6a0c2..6c1b418 100644
--- a/internal/test/server.go
+++ b/internal/test/server.go
@@ -10,13 +10,14 @@ import (
httpw "github.com/eduvpn/eduvpn-common/internal/http"
)
+// Server wraps a HTTP test server
type Server struct {
*httptest.Server
}
+// NewServer creates a new test server
func NewServer(handler http.Handler) *Server {
s := httptest.NewTLSServer(handler)
-
return &Server{s}
}
diff --git a/internal/version/version.go b/internal/version/version.go
index 1f029d5..c71af9e 100644
--- a/internal/version/version.go
+++ b/internal/version/version.go
@@ -1,3 +1,9 @@
+// Package version defines a version string that is used for:
+// - building
+// - the user agent
+// - tagging
package version
+// Version is the latest version
+// Update this when releasing
const Version = "2.0.0"
diff --git a/internal/wireguard/ini/ini.go b/internal/wireguard/ini/ini.go
index 6791336..597fd83 100644
--- a/internal/wireguard/ini/ini.go
+++ b/internal/wireguard/ini/ini.go
@@ -1,4 +1,4 @@
-// package ini implements an opinionated ini parser that only implements what we exactly need for WireGuard configs
+// Package ini implements an opinionated ini parser that only implements what we exactly need for WireGuard configs
// - key/values MUST live under a section
// - empty section names are NOT allowed
// - comments are indicated with a #
diff --git a/internal/wireguard/wireguard.go b/internal/wireguard/wireguard.go
index af290ea..e94a485 100644
--- a/internal/wireguard/wireguard.go
+++ b/internal/wireguard/wireguard.go
@@ -36,12 +36,17 @@ func availableUDPPort() (int, error) {
return ludp.LocalAddr().(*net.UDPAddr).Port, nil
}
+// Proxy is the proxyguard information
type Proxy struct {
+ // SourcePort is the source port of the TCP socket
SourcePort int
- Listen string
- Peer string
+ // Listen is the IP:PORT of the udp listener
+ Listen string
+ // Peer is the hostname/ip:port of the WireGuard peer
+ Peer string
}
+// Config gets a wireguard config with API config `cfg`, wg key `key` and prefer tcp `tcp`
func Config(cfg string, key *wgtypes.Key, tcp bool) (string, *Proxy, error) {
// the key is nil if the client does not accept WireGuard
if key == nil {
diff --git a/types/cookie/cookie.go b/types/cookie/cookie.go
index 1714682..48c8dbf 100644
--- a/types/cookie/cookie.go
+++ b/types/cookie/cookie.go
@@ -1,4 +1,4 @@
-// package cookie implements a specialized version of a context
+// Package cookie implements a specialized version of a context
// - It is cancellable
// - It has a channel associated with it to reply to state callbacks
// - It can be marshalled by having a cgo Handle attached to it
@@ -12,6 +12,8 @@ import (
"runtime/cgo"
)
+// Cookie is the cookie which is just a context with some other data associated with it
+// We could potentially only uses contexts with values, but this is nicer for type checking
type Cookie struct {
c chan string
ctx context.Context
@@ -19,8 +21,10 @@ type Cookie struct {
H cgo.Handle
}
+// contextt is the context type for the value
type contextt int8
+// CONTEXTK is the key of the cookie
const CONTEXTK contextt = 0
// NewWithContext creates a new cookie with a context
diff --git a/types/discovery/discovery.go b/types/discovery/discovery.go
index bc22eab..cadd192 100644
--- a/types/discovery/discovery.go
+++ b/types/discovery/discovery.go
@@ -1,4 +1,4 @@
-// package discovery defines the public types that have to deal with discovery
+// Package discovery defines the public types that have to deal with discovery
package discovery
import (
@@ -70,7 +70,7 @@ type Server struct {
// This library always marshals the data as a map and then makes sure unmarshalling also gives a map
type MapOrString map[string]string
-// The display name can either be a map or a string in the server list
+// UnmarshalJSON unmarshals the display name. It can either be a map or a string in the server list
// Unmarshal it by first trying a string and then the map.
func (displayName *MapOrString) UnmarshalJSON(data []byte) error {
var displayNameString string
diff --git a/types/error/error.go b/types/error/error.go
index 9697e9d..7723c97 100644
--- a/types/error/error.go
+++ b/types/error/error.go
@@ -1,3 +1,4 @@
+// Package err defines public error types that are returned to clients
package err
// Translated defines the type for translated strings
diff --git a/types/protocol/protocol.go b/types/protocol/protocol.go
index 3967141..85b0733 100644
--- a/types/protocol/protocol.go
+++ b/types/protocol/protocol.go
@@ -1,4 +1,4 @@
-// package protocol contains hte public type that have to do with VPN protocols
+// Package protocol contains hte public type that have to do with VPN protocols
package protocol
// Protocol defines an 'enumeration' of protocols
diff --git a/types/server/server.go b/types/server/server.go
index 5e1fa9b..1beb8fb 100644
--- a/types/server/server.go
+++ b/types/server/server.go
@@ -1,4 +1,4 @@
-// package server defines public types that have to deal with the VPN server
+// Package server defines public types that have to deal with the VPN server
package server
import (
@@ -23,7 +23,7 @@ const (
TypeCustom
)
-// This is here to support V1 configs which had the server type as a string
+// UnmarshalJSON is set here here to support V1 configs which had the server type as a string
func (t *Type) UnmarshalJSON(data []byte) error {
// First try to just unmarshal the type
var num int8