summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Wijenbergh <jeroen.wijenbergh@geant.org>2025-08-25 10:59:37 +0200
committerJeroen Wijenbergh <jeroen.wijenbergh@geant.org>2025-08-25 13:06:41 +0200
commit27b95b4911da055fe9b5fb37b5fb4a33eda6b989 (patch)
treef6eb1143fa9bd2995d671b71d75c950e2c703660
parentb4f4f5600298436c63b89f289c318d777300c499 (diff)
All: Remove util packages
Was giving linting errors and it's not a good idea anyways
-rw-r--r--client/client.go28
-rw-r--r--client/client_test.go76
-rw-r--r--client/discovery.go2
-rw-r--r--client/fsm.go2
-rw-r--r--cmd/eduvpn-cli/main.go4
-rw-r--r--exports/exports.go5
-rw-r--r--exports/exports_test_wrapper.go4
-rw-r--r--i18n/err/i18nerr.go (renamed from i18nerr/i18nerr.go)0
-rw-r--r--i18n/i18n.go (renamed from util/util.go)36
-rw-r--r--i18n/i18n_test.go47
-rw-r--r--internal/config/config.go3
-rw-r--r--internal/log/log.go4
-rw-r--r--internal/server/secureinternet.go32
-rw-r--r--internal/server/secureinternet_test.go (renamed from internal/util/util_test.go)2
-rw-r--r--internal/util/util.go44
-rw-r--r--util/util_test.go126
16 files changed, 193 insertions, 222 deletions
diff --git a/client/client.go b/client/client.go
index d668eb0..59b425d 100644
--- a/client/client.go
+++ b/client/client.go
@@ -7,11 +7,12 @@ import (
"context"
"errors"
"log/slog"
+ "net"
"os"
"sync"
"time"
- "codeberg.org/eduVPN/eduvpn-common/i18nerr"
+ "codeberg.org/eduVPN/eduvpn-common/i18n/err"
"codeberg.org/eduVPN/eduvpn-common/internal/api"
"codeberg.org/eduVPN/eduvpn-common/internal/config"
"codeberg.org/eduVPN/eduvpn-common/internal/discovery"
@@ -25,6 +26,31 @@ import (
"github.com/jwijenbergh/eduoauth-go"
)
+// CalculateGateway takes a CIDR encoded subnet `cidr` and returns the gateway and an error
+// TODO: move this somewhere else?
+func CalculateGateway(cidr string) (string, error) {
+ _, ipn, err := net.ParseCIDR(cidr)
+ if err != nil {
+ return "", i18nerr.WrapInternalf(err, "failed to parse CIDR for calculating gateway: %v", cidr)
+ }
+
+ ret := make(net.IP, len(ipn.IP))
+ copy(ret, ipn.IP)
+
+ for i := len(ret) - 1; i >= 0; i-- {
+ ret[i]++
+ if ret[i] > 0 {
+ break
+ }
+ }
+
+ if !ipn.Contains(ret) {
+ return "", i18nerr.Newf("IP network does not contain incremented IP: %v", ret)
+ }
+
+ return ret.String(), nil
+}
+
// Client is the main struct for the VPN client.
type Client struct {
// The name of the client
diff --git a/client/client_test.go b/client/client_test.go
index 9f302c4..d623037 100644
--- a/client/client_test.go
+++ b/client/client_test.go
@@ -11,12 +11,88 @@ import (
"time"
httpw "codeberg.org/eduVPN/eduvpn-common/internal/http"
+ "codeberg.org/eduVPN/eduvpn-common/internal/test"
"codeberg.org/eduVPN/eduvpn-common/types/cookie"
"codeberg.org/eduVPN/eduvpn-common/types/protocol"
srvtypes "codeberg.org/eduVPN/eduvpn-common/types/server"
"github.com/jwijenbergh/eduoauth-go"
)
+func TestCalculateGateway(t *testing.T) {
+ cases := []struct {
+ in string
+ want string
+ err string
+ }{
+ // normal cases
+ {
+ in: "10.10.10.5/24",
+ want: "10.10.10.1",
+ err: "",
+ },
+ {
+ in: "10.10.10.130/25",
+ want: "10.10.10.129",
+ err: "",
+ },
+ {
+ in: "fd42::5/112",
+ want: "fd42::1",
+ err: "",
+ },
+ {
+ in: "5502:df9::/64",
+ want: "5502:df9::1",
+ err: "",
+ },
+ // unrealistic scenario but we have to handle these!
+ {
+ in: "5502:df9::0/128",
+ want: "",
+ err: "IP network does not contain incremented IP: 5502:df9::1",
+ },
+ {
+ in: "5502:df9::ffff/128",
+ want: "",
+ err: "IP network does not contain incremented IP: 5502:df9::1:0",
+ },
+ {
+ in: "10.0.0.0/32",
+ want: "",
+ err: "IP network does not contain incremented IP: 10.0.0.1",
+ },
+ {
+ in: "10.0.0.255/32",
+ want: "",
+ err: "IP network does not contain incremented IP: 10.0.1.0",
+ },
+ // parsing errors
+ {
+ in: "10.0.0.1",
+ want: "",
+ err: "An internal error occurred. The cause of the error is: invalid CIDR address: 10.0.0.1.",
+ },
+ {
+ in: "bla",
+ want: "",
+ err: "An internal error occurred. The cause of the error is: invalid CIDR address: bla.",
+ },
+ {
+ in: "5502:df9::ffff",
+ want: "",
+ err: "An internal error occurred. The cause of the error is: invalid CIDR address: 5502:df9::ffff.",
+ },
+ }
+
+ for _, c := range cases {
+ got, err := CalculateGateway(c.in)
+ test.AssertError(t, err, c.err)
+ if got != c.want {
+ t.Fatalf("got: %v not equal to want: %v", got, c.want)
+ }
+ }
+}
+
func getServerURI(t *testing.T) string {
serverURI := os.Getenv("SERVER_URI")
if serverURI == "" {
diff --git a/client/discovery.go b/client/discovery.go
index b1cae32..b434025 100644
--- a/client/discovery.go
+++ b/client/discovery.go
@@ -5,7 +5,7 @@ import (
"sort"
"strings"
- "codeberg.org/eduVPN/eduvpn-common/i18nerr"
+ "codeberg.org/eduVPN/eduvpn-common/i18n/err"
"codeberg.org/eduVPN/eduvpn-common/types/cookie"
discotypes "codeberg.org/eduVPN/eduvpn-common/types/discovery"
)
diff --git a/client/fsm.go b/client/fsm.go
index 6fffc8a..673f3fb 100644
--- a/client/fsm.go
+++ b/client/fsm.go
@@ -4,7 +4,7 @@ import (
"fmt"
"log/slog"
- "codeberg.org/eduVPN/eduvpn-common/i18nerr"
+ "codeberg.org/eduVPN/eduvpn-common/i18n/err"
"codeberg.org/eduVPN/eduvpn-common/internal/fsm"
)
diff --git a/cmd/eduvpn-cli/main.go b/cmd/eduvpn-cli/main.go
index 2dd0c31..92c37f5 100644
--- a/cmd/eduvpn-cli/main.go
+++ b/cmd/eduvpn-cli/main.go
@@ -10,10 +10,10 @@ import (
"strings"
"codeberg.org/eduVPN/eduvpn-common/client"
+ "codeberg.org/eduVPN/eduvpn-common/i18n"
"codeberg.org/eduVPN/eduvpn-common/internal/version"
"codeberg.org/eduVPN/eduvpn-common/types/cookie"
srvtypes "codeberg.org/eduVPN/eduvpn-common/types/server"
- "codeberg.org/eduVPN/eduvpn-common/util"
"github.com/pkg/browser"
)
@@ -39,7 +39,7 @@ func getProfileInteractive(profiles *srvtypes.Profiles, data any) (string, error
var options []string
i := 0
for k, v := range profiles.Map {
- ps += fmt.Sprintf("\n%d - %s", i+1, util.GetLanguageMatched(v.DisplayName, "en"))
+ ps += fmt.Sprintf("\n%d - %s", i+1, i18n.GetLanguageMatched(v.DisplayName, "en"))
options = append(options, k)
i++
}
diff --git a/exports/exports.go b/exports/exports.go
index 47b9f14..9be3b66 100644
--- a/exports/exports.go
+++ b/exports/exports.go
@@ -26,11 +26,10 @@ import (
"unsafe"
"codeberg.org/eduVPN/eduvpn-common/client"
- "codeberg.org/eduVPN/eduvpn-common/i18nerr"
+ "codeberg.org/eduVPN/eduvpn-common/i18n/err"
"codeberg.org/eduVPN/eduvpn-common/types/cookie"
errtypes "codeberg.org/eduVPN/eduvpn-common/types/error"
srvtypes "codeberg.org/eduVPN/eduvpn-common/types/server"
- "codeberg.org/eduVPN/eduvpn-common/util"
)
// goString copies a null-terminated *C.char to a Go string.
@@ -1053,7 +1052,7 @@ func SetTokenHandler(getter C.TokenGetter, setter C.TokenSetter) *C.char {
//
//export CalculateGateway
func CalculateGateway(subnet *C.char) (*C.char, *C.char) {
- gw, err := util.CalculateGateway(goString(subnet))
+ gw, err := client.CalculateGateway(goString(subnet))
if err != nil {
return nil, getCError(err)
}
diff --git a/exports/exports_test_wrapper.go b/exports/exports_test_wrapper.go
index de6aa21..0c9b9dc 100644
--- a/exports/exports_test_wrapper.go
+++ b/exports/exports_test_wrapper.go
@@ -21,9 +21,9 @@ import (
"testing"
"time"
+ "codeberg.org/eduVPN/eduvpn-common/i18n"
"codeberg.org/eduVPN/eduvpn-common/internal/test"
"codeberg.org/eduVPN/eduvpn-common/types/error"
- "codeberg.org/eduVPN/eduvpn-common/util"
httpw "codeberg.org/eduVPN/eduvpn-common/internal/http"
)
@@ -49,7 +49,7 @@ func getError(t *testing.T, gerr *C.char) string {
t.Fatalf("failed getting error JSON, val: %v, err: %v", jsonErr, jerr)
}
- return util.GetLanguageMatched(transl.Message, "en")
+ return i18n.GetLanguageMatched(transl.Message, "en")
}
// ClonedAskTransition is a clone of the struct types/server.go RequiredAskTransition
diff --git a/i18nerr/i18nerr.go b/i18n/err/i18nerr.go
index 8254dd4..8254dd4 100644
--- a/i18nerr/i18nerr.go
+++ b/i18n/err/i18nerr.go
diff --git a/util/util.go b/i18n/i18n.go
index 4609199..02b9028 100644
--- a/util/util.go
+++ b/i18n/i18n.go
@@ -1,37 +1,7 @@
-// Package util defines public utility functions to be used by applications
-// these are outside of the client package as they can be used even if a client hasn't been created yet
-package util
+// Package i18n implements utility functions for internationalization
+package i18n
-import (
- "net"
- "strings"
-
- "codeberg.org/eduVPN/eduvpn-common/i18nerr"
-)
-
-// CalculateGateway takes a CIDR encoded subnet `cidr` and returns the gateway and an error
-func CalculateGateway(cidr string) (string, error) {
- _, ipn, err := net.ParseCIDR(cidr)
- if err != nil {
- return "", i18nerr.WrapInternalf(err, "failed to parse CIDR for calculating gateway: %v", cidr)
- }
-
- ret := make(net.IP, len(ipn.IP))
- copy(ret, ipn.IP)
-
- for i := len(ret) - 1; i >= 0; i-- {
- ret[i]++
- if ret[i] > 0 {
- break
- }
- }
-
- if !ipn.Contains(ret) {
- return "", i18nerr.Newf("IP network does not contain incremented IP: %v", ret)
- }
-
- return ret.String(), nil
-}
+import "strings"
// GetLanguageMatched uses a map from language tags to strings to extract the right language given the tag
// It implements it according to https://github.com/eduvpn/documentation/blob/dc4d53c47dd7a69e95d6650eec408e16eaa814a2/SERVER_DISCOVERY.md#language-matching
diff --git a/i18n/i18n_test.go b/i18n/i18n_test.go
new file mode 100644
index 0000000..fc671a4
--- /dev/null
+++ b/i18n/i18n_test.go
@@ -0,0 +1,47 @@
+package i18n
+
+import "testing"
+
+func TestGetLanguageMatched(t *testing.T) {
+ // exact match
+ returned := GetLanguageMatched(map[string]string{"en": "test", "de": "test2"}, "en")
+ if returned != "test" {
+ t.Fatalf("Got: %s, want: %s", returned, "test")
+ }
+
+ // starts with language tag
+ returned = GetLanguageMatched(map[string]string{"en-US-test": "test", "de": "test2"}, "en-US")
+ if returned != "test" {
+ t.Fatalf("Got: %s, want: %s", returned, "test")
+ }
+
+ // starts with en-
+ returned = GetLanguageMatched(map[string]string{"en-UK": "test", "en": "test2"}, "en-US")
+ if returned != "test" {
+ t.Fatalf("Got: %s, want: %s", returned, "test")
+ }
+
+ // exact match for en
+ returned = GetLanguageMatched(map[string]string{"de": "test", "en": "test2"}, "en-US")
+ if returned != "test2" {
+ t.Fatalf("Got: %s, want: %s", returned, "test2")
+ }
+
+ // We default to english
+ returned = GetLanguageMatched(map[string]string{"es": "test", "en": "test2"}, "nl-NL")
+ if returned != "test2" {
+ t.Fatalf("Got: %s, want: %s", returned, "test2")
+ }
+
+ // We default to english with a - as well
+ returned = GetLanguageMatched(map[string]string{"est": "test", "en-": "test2"}, "en-US")
+ if returned != "test2" {
+ t.Fatalf("Got: %s, want: %s", returned, "test2")
+ }
+
+ // None found just return one
+ returned = GetLanguageMatched(map[string]string{"es": "test"}, "en-US")
+ if returned != "test" {
+ t.Fatalf("Got: %s, want: %s", returned, "test")
+ }
+}
diff --git a/internal/config/config.go b/internal/config/config.go
index 06da9b3..e324ebb 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -12,7 +12,6 @@ import (
"codeberg.org/eduVPN/eduvpn-common/internal/config/v1"
"codeberg.org/eduVPN/eduvpn-common/internal/config/v2"
"codeberg.org/eduVPN/eduvpn-common/internal/discovery"
- "codeberg.org/eduVPN/eduvpn-common/internal/util"
)
const stateFile = "state.json"
@@ -40,7 +39,7 @@ func (c *Config) HasSecureInternet() bool {
// Save saves the state file to disk
func (c *Config) Save() error {
- if err := util.EnsureDirectory(c.directory); err != nil {
+ if err := os.MkdirAll(c.directory, 0o700); err != nil {
return err
}
diff --git a/internal/log/log.go b/internal/log/log.go
index 47cdcf3..53671b3 100644
--- a/internal/log/log.go
+++ b/internal/log/log.go
@@ -7,8 +7,6 @@ import (
"log/slog"
"os"
"path"
-
- "codeberg.org/eduVPN/eduvpn-common/internal/util"
)
// Init initializes the logger by setting a max level 'level' and a directory 'directory' where the log should be stored
@@ -17,7 +15,7 @@ import (
// It returns the log file and the error
// This log file should be closed at the end
func Init(lvl slog.Level, dir string) (*os.File, error) {
- err := util.EnsureDirectory(dir)
+ err := os.MkdirAll(dir, 0o700)
if err != nil {
return nil, err
}
diff --git a/internal/server/secureinternet.go b/internal/server/secureinternet.go
index f97cef1..e0d081a 100644
--- a/internal/server/secureinternet.go
+++ b/internal/server/secureinternet.go
@@ -4,16 +4,42 @@ import (
"context"
"errors"
"log/slog"
+ "net/url"
+ "strings"
"time"
"codeberg.org/eduVPN/eduvpn-common/internal/api"
"codeberg.org/eduVPN/eduvpn-common/internal/config/v2"
"codeberg.org/eduVPN/eduvpn-common/internal/discovery"
- "codeberg.org/eduVPN/eduvpn-common/internal/util"
"codeberg.org/eduVPN/eduvpn-common/types/server"
"github.com/jwijenbergh/eduoauth-go"
)
+// ReplaceWAYF replaces an authorization template containing of @RETURN_TO@ and @ORG_ID@ with the authorization URL and the organization ID
+// See https://github.com/eduvpn/documentation/blob/dc4d53c47dd7a69e95d6650eec408e16eaa814a2/SERVER_DISCOVERY_SKIP_WAYF.md
+func ReplaceWAYF(template string, authURL string, orgID string) string {
+ // We just return the authURL in the cases where the template is not given or is invalid
+ if template == "" {
+ return authURL
+ }
+ if !strings.Contains(template, "@RETURN_TO@") {
+ return authURL
+ }
+ if !strings.Contains(template, "@ORG_ID@") {
+ return authURL
+ }
+ // Replace authURL
+ template = strings.Replace(template, "@RETURN_TO@", url.QueryEscape(authURL), 1)
+
+ // If now there is no more ORG_ID, return as there weren't enough @ symbols
+ if !strings.Contains(template, "@ORG_ID@") {
+ return authURL
+ }
+ // Replace ORG ID
+ template = strings.Replace(template, "@ORG_ID@", url.QueryEscape(orgID), 1)
+ return template
+}
+
// AddSecure adds a secure internet server
// `ctx` is the context used for cancellation
// `disco` are the discovery servers
@@ -47,7 +73,7 @@ func (s *Servers) AddSecure(ctx context.Context, discom *discovery.Manager, orgI
if err != nil {
return "", err
}
- ret := util.ReplaceWAYF(updsrv.AuthenticationURLTemplate, url, updorg.OrgID)
+ ret := ReplaceWAYF(updsrv.AuthenticationURLTemplate, url, updorg.OrgID)
return ret, nil
},
}
@@ -127,7 +153,7 @@ func (s *Servers) GetSecure(ctx context.Context, orgID string, discom *discovery
if err != nil {
return "", err
}
- ret := util.ReplaceWAYF(updsrv.AuthenticationURLTemplate, url, updorg.OrgID)
+ ret := ReplaceWAYF(updsrv.AuthenticationURLTemplate, url, updorg.OrgID)
return ret, nil
},
DisableAuthorize: disableAuth,
diff --git a/internal/util/util_test.go b/internal/server/secureinternet_test.go
index 827fbe1..8a4466e 100644
--- a/internal/util/util_test.go
+++ b/internal/server/secureinternet_test.go
@@ -1,4 +1,4 @@
-package util
+package server
import "testing"
diff --git a/internal/util/util.go b/internal/util/util.go
deleted file mode 100644
index 97b4151..0000000
--- a/internal/util/util.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Package util implements several utility functions that are used across the codebase
-package util
-
-import (
- "fmt"
- "net/url"
- "os"
- "strings"
-)
-
-// EnsureDirectory creates a directory with permission 700.
-func EnsureDirectory(dir string) error {
- // Create with 700 permissions, read, write, execute only for the owner
- err := os.MkdirAll(dir, 0o700)
- if err != nil {
- return fmt.Errorf("failed to create directory '%s' with error: %w", dir, err)
- }
- return nil
-}
-
-// ReplaceWAYF replaces an authorization template containing of @RETURN_TO@ and @ORG_ID@ with the authorization URL and the organization ID
-// See https://github.com/eduvpn/documentation/blob/dc4d53c47dd7a69e95d6650eec408e16eaa814a2/SERVER_DISCOVERY_SKIP_WAYF.md
-func ReplaceWAYF(template string, authURL string, orgID string) string {
- // We just return the authURL in the cases where the template is not given or is invalid
- if template == "" {
- return authURL
- }
- if !strings.Contains(template, "@RETURN_TO@") {
- return authURL
- }
- if !strings.Contains(template, "@ORG_ID@") {
- return authURL
- }
- // Replace authURL
- template = strings.Replace(template, "@RETURN_TO@", url.QueryEscape(authURL), 1)
-
- // If now there is no more ORG_ID, return as there weren't enough @ symbols
- if !strings.Contains(template, "@ORG_ID@") {
- return authURL
- }
- // Replace ORG ID
- template = strings.Replace(template, "@ORG_ID@", url.QueryEscape(orgID), 1)
- return template
-}
diff --git a/util/util_test.go b/util/util_test.go
deleted file mode 100644
index fd35088..0000000
--- a/util/util_test.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package util
-
-import (
- "testing"
-
- "codeberg.org/eduVPN/eduvpn-common/internal/test"
-)
-
-func TestCalculateGateway(t *testing.T) {
- cases := []struct {
- in string
- want string
- err string
- }{
- // normal cases
- {
- in: "10.10.10.5/24",
- want: "10.10.10.1",
- err: "",
- },
- {
- in: "10.10.10.130/25",
- want: "10.10.10.129",
- err: "",
- },
- {
- in: "fd42::5/112",
- want: "fd42::1",
- err: "",
- },
- {
- in: "5502:df9::/64",
- want: "5502:df9::1",
- err: "",
- },
- // unrealistic scenario but we have to handle these!
- {
- in: "5502:df9::0/128",
- want: "",
- err: "IP network does not contain incremented IP: 5502:df9::1",
- },
- {
- in: "5502:df9::ffff/128",
- want: "",
- err: "IP network does not contain incremented IP: 5502:df9::1:0",
- },
- {
- in: "10.0.0.0/32",
- want: "",
- err: "IP network does not contain incremented IP: 10.0.0.1",
- },
- {
- in: "10.0.0.255/32",
- want: "",
- err: "IP network does not contain incremented IP: 10.0.1.0",
- },
- // parsing errors
- {
- in: "10.0.0.1",
- want: "",
- err: "An internal error occurred. The cause of the error is: invalid CIDR address: 10.0.0.1.",
- },
- {
- in: "bla",
- want: "",
- err: "An internal error occurred. The cause of the error is: invalid CIDR address: bla.",
- },
- {
- in: "5502:df9::ffff",
- want: "",
- err: "An internal error occurred. The cause of the error is: invalid CIDR address: 5502:df9::ffff.",
- },
- }
-
- for _, c := range cases {
- got, err := CalculateGateway(c.in)
- test.AssertError(t, err, c.err)
- if got != c.want {
- t.Fatalf("got: %v not equal to want: %v", got, c.want)
- }
- }
-}
-
-func TestGetLanguageMatched(t *testing.T) {
- // exact match
- returned := GetLanguageMatched(map[string]string{"en": "test", "de": "test2"}, "en")
- if returned != "test" {
- t.Fatalf("Got: %s, want: %s", returned, "test")
- }
-
- // starts with language tag
- returned = GetLanguageMatched(map[string]string{"en-US-test": "test", "de": "test2"}, "en-US")
- if returned != "test" {
- t.Fatalf("Got: %s, want: %s", returned, "test")
- }
-
- // starts with en-
- returned = GetLanguageMatched(map[string]string{"en-UK": "test", "en": "test2"}, "en-US")
- if returned != "test" {
- t.Fatalf("Got: %s, want: %s", returned, "test")
- }
-
- // exact match for en
- returned = GetLanguageMatched(map[string]string{"de": "test", "en": "test2"}, "en-US")
- if returned != "test2" {
- t.Fatalf("Got: %s, want: %s", returned, "test2")
- }
-
- // We default to english
- returned = GetLanguageMatched(map[string]string{"es": "test", "en": "test2"}, "nl-NL")
- if returned != "test2" {
- t.Fatalf("Got: %s, want: %s", returned, "test2")
- }
-
- // We default to english with a - as well
- returned = GetLanguageMatched(map[string]string{"est": "test", "en-": "test2"}, "en-US")
- if returned != "test2" {
- t.Fatalf("Got: %s, want: %s", returned, "test2")
- }
-
- // None found just return one
- returned = GetLanguageMatched(map[string]string{"es": "test"}, "en-US")
- if returned != "test" {
- t.Fatalf("Got: %s, want: %s", returned, "test")
- }
-}