summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorjwijenbergh <jeroenwijenbergh@protonmail.com>2024-02-12 19:18:05 +0100
committerJeroen Wijenbergh <46386452+jwijenbergh@users.noreply.github.com>2024-02-19 14:15:07 +0100
commit74e36f0ead717105f26087c2cab08b41ba5a7ce8 (patch)
tree1eb2b7516bea705c9b5a50ce0965e170414ed880 /internal
parent682d70091af2044ff6d8b350da9dff13163232e2 (diff)
All: Document everything to pass revive lint
Diffstat (limited to 'internal')
-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
28 files changed, 303 insertions, 83 deletions
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 {