diff --git a/.github/workflows/integrationtest.yml b/.github/workflows/integrationtest.yml index 7822cbd..ebb63de 100644 --- a/.github/workflows/integrationtest.yml +++ b/.github/workflows/integrationtest.yml @@ -26,20 +26,21 @@ jobs: cd ../plexus-agent CGO_ENABLED=0 go build -v . - #tests: - # runs-on: ubuntu-latest - # if: ${{ github.actor != 'dependabot[bot]' }} - # steps: - # - name: Checkout - # uses: actions/checkout@v4 - # - name: Setup Go - # uses: actions/setup-go@v6 - # with: - # go-version-file: ./go.mod - # - name: run tests - # run: | - # go vet ./... - # go test ./... -v + tests: + runs-on: ubuntu-latest + if: ${{ github.actor != 'dependabot[bot]' }} + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v6 + with: + go-version-file: ./go.mod + - name: run tests + run: | + go vet ./... + sudo go test -v ./... + lint: diff --git a/.gitignore b/.gitignore index 338c063..3088c65 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ time.db **/launch.json devops/experiment/* devops/plexus-update/* -devops/deploy/* \ No newline at end of file +devops/deploy/* +internal/agent/agent.seed \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index d3f59b4..c9e097f 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -19,35 +19,40 @@ linters: - noinlineerr - paralleltest - testpackage - - thelper - wrapcheck - wsl - wsl_v5 settings: cyclop: max-complexity: 20 + errcheck: + exclude-functions: + - crypto/rand.Read funlen: statements: 60 - lines: 80 + lines: 82 gosmopolitan: allow-time-local: true ireturn: allow: - - nkeys.KeyPair - error + - io.Reader + - net/http.Handler + - nkeys.KeyPair varnamelen: max-distance: 15 ignore-names: - i - wg ignore-decls: - - c *gin.Context - c *nftables.Conn - c nftables.Conn - ec *nats.Conn - f embed.FS - id string - ns *server.Server + - r *http.Request + - w http.ResponseWriter exclusions: warn-unused: true generated: lax @@ -59,23 +64,18 @@ linters: rules: - path: _test\.go linters: + - dupl + - funlen - gocognit - goconst - - funlen - - nonamedreturns - - revive - predeclared - - path: app/plexus-agent/cmd/ - linters: - revive - - path: wireguard.go + - path: app/plexus-agent/cmd/* linters: - revive formatters: enable: - - gci - - gofmt - gofumpt - - goimports + - golines exclusions: generated: lax diff --git a/README.md b/README.md index e7bae57..9a7e2c2 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Agent Tech Stack ========== * Language: [Go](https://go.dev) -* HTTP Framework: [Gin](https://github.com/gin-gonic/gin) +* HTTP Router: [devilcove/mux](https://github.com/devilcove/mux) * FrontEnd Framework: html/[htmx](https://htmx.org) * CSS Library: [w3schools](https://w3schools.com/w3css) * Database(key/value): [bbolt](https://github.com/etcd-io/bbolt) diff --git a/app/plexus-agent/cmd/drop.go b/app/plexus-agent/cmd/drop.go index 4161ce3..f605c88 100644 --- a/app/plexus-agent/cmd/drop.go +++ b/app/plexus-agent/cmd/drop.go @@ -46,5 +46,6 @@ var dropCmd = &cobra.Command{ func init() { rootCmd.AddCommand(dropCmd) - statusCmd.Flags().BoolVarP(&force, "force", "f", false, "force deletion even when not connected") + statusCmd.Flags(). + BoolVarP(&force, "force", "f", false, "force deletion even when not connected") } diff --git a/app/plexus-agent/cmd/register.go b/app/plexus-agent/cmd/register.go index e61fa57..5288a03 100644 --- a/app/plexus-agent/cmd/register.go +++ b/app/plexus-agent/cmd/register.go @@ -36,7 +36,9 @@ var registerCmd = &cobra.Command{ ec, err := agent.ConnectToAgentBroker() cobra.CheckErr(err) resp := plexus.MessageResponse{} - cobra.CheckErr(agent.Request(ec, agent.Agent+plexus.Register, request, &resp, agent.NatsTimeout)) + cobra.CheckErr( + agent.Request(ec, agent.Agent+plexus.Register, request, &resp, agent.NatsTimeout), + ) fmt.Println(resp.Message) }, } diff --git a/app/plexus-agent/cmd/reset.go b/app/plexus-agent/cmd/reset.go index 3c1c28a..895aed0 100644 --- a/app/plexus-agent/cmd/reset.go +++ b/app/plexus-agent/cmd/reset.go @@ -38,7 +38,9 @@ var resetCmd = &cobra.Command{ ec, err := agent.ConnectToAgentBroker() cobra.CheckErr(err) resp := plexus.MessageResponse{} - cobra.CheckErr(agent.Request(ec, agent.Agent+plexus.Reset, request, &resp, agent.NatsTimeout)) + cobra.CheckErr( + agent.Request(ec, agent.Agent+plexus.Reset, request, &resp, agent.NatsTimeout), + ) fmt.Println(resp.Message) }, } diff --git a/app/plexus-agent/cmd/root.go b/app/plexus-agent/cmd/root.go index fff15bb..18dc36b 100644 --- a/app/plexus-agent/cmd/root.go +++ b/app/plexus-agent/cmd/root.go @@ -16,18 +16,17 @@ limitations under the License. package cmd import ( - "fmt" - "log" "log/slog" "os" + "path/filepath" "runtime/debug" + "github.com/devilcove/plexus" "github.com/devilcove/plexus/internal/agent" "github.com/spf13/cobra" - "github.com/spf13/viper" ) -var config agent.Configuration +// var config agent.Configuration // rootCmd represents the base command when called without any subcommands. var rootCmd = &cobra.Command{ @@ -57,9 +56,9 @@ func init() { // Cobra supports persistent flags, which, if defined here, // will be global for your application. - rootCmd.PersistentFlags().StringP("verbosity", "v", "INFO", "logging verbosity") - rootCmd.PersistentFlags().IntP("natsport", "p", 4223, "nats port for cli <-> agent comms") - + agent.Config.Verbosity = *rootCmd.PersistentFlags().StringP("verbosity", "v", "INFO", "logging verbosity") + agent.Config.NatsPort = *rootCmd.PersistentFlags().IntP("natsport", "p", 4223, "nats port for cli <-> agent comms") + plexus.SetLogging(agent.Config.Verbosity) // Cobra also supports local flags, which will only run // when this action is called directly. // rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") @@ -67,21 +66,14 @@ func init() { // initConfig reads in config file and ENV variables if set. func initConfig() { - viper.SetConfigFile("/etc/plexus-agent/config") - viper.SetConfigType("yaml") - - if err := viper.BindPFlags(rootCmd.Flags()); err != nil { - log.Println("bindflags", err) - } - viper.SetEnvPrefix("PLEXUS") - viper.AutomaticEnv() // read in environment variables that match - if err := viper.ReadInConfig(); err == nil { - fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) - } - if err := viper.UnmarshalExact(&config); err != nil { - log.Println("viper.Unmarshal", err) + plexus.SetLogging("INFO") + home, err := os.UserHomeDir() + if err != nil { + panic(err) } - agent.Config = config - slog.Debug("using configuration", "config", config) + agent.Config.DataDir = home + "/.local/share/" + filepath.Base(os.Args[0]) + "/" + + // set defaults + slog.Debug("using configuration", "config", agent.Config) debug.SetTraceback("single") } diff --git a/app/plexus-agent/cmd/set.go b/app/plexus-agent/cmd/set.go index 965bce8..9ca4c79 100644 --- a/app/plexus-agent/cmd/set.go +++ b/app/plexus-agent/cmd/set.go @@ -67,7 +67,15 @@ var setCmd = &cobra.Command{ resp := plexus.MessageResponse{} ec, err := agent.ConnectToAgentBroker() cobra.CheckErr(err) - cobra.CheckErr(agent.Request(ec, agent.Agent+plexus.SetPrivateEndpoint, request, &resp, agent.NatsTimeout)) + cobra.CheckErr( + agent.Request( + ec, + agent.Agent+plexus.SetPrivateEndpoint, + request, + &resp, + agent.NatsTimeout, + ), + ) fmt.Println(resp.Message) }, } diff --git a/app/plexus-agent/cmd/status.go b/app/plexus-agent/cmd/status.go index 71074cc..9cd9be2 100644 --- a/app/plexus-agent/cmd/status.go +++ b/app/plexus-agent/cmd/status.go @@ -44,7 +44,9 @@ var statusCmd = &cobra.Command{ cobra.CheckErr(err) status := agent.StatusResponse{} // networks := []Network{} - cobra.CheckErr(agent.Request(ec, agent.Agent+plexus.Status, nil, &status, agent.NatsTimeout)) + cobra.CheckErr( + agent.Request(ec, agent.Agent+plexus.Status, nil, &status, agent.NatsTimeout), + ) if status.Server == "" { fmt.Println("agent running... not connected to servers") return @@ -105,7 +107,11 @@ var statusCmd = &cobra.Command{ fmt.Println("\trelay: true") showRelayedPeers(peer.RelayedPeers, network) } - fmt.Println("\tprivate-endpoint:", peer.PrivateEndpoint.String()+":", peer.ListenPort) + fmt.Println( + "\tprivate-endpoint:", + peer.PrivateEndpoint.String()+":", + peer.ListenPort, + ) fmt.Println("\tpublic-endpoint:", peer.Endpoint.String()+":", peer.PublicListenPort) fmt.Println("\twg-endpoint:", wgPeer.Endpoint) fmt.Print("\tallowed ips:") diff --git a/app/plexus-agent/cmd/status_test.go b/app/plexus-agent/cmd/status_test.go index f9ee3b9..2190635 100644 --- a/app/plexus-agent/cmd/status_test.go +++ b/app/plexus-agent/cmd/status_test.go @@ -11,47 +11,47 @@ import ( func TestPrintHandshake(t *testing.T) { bytes := make([]byte, 128) out, err := os.Open(os.Stdout.Name()) - should.BeNil(t, err) + should.NotBeError(t, err) t.Run("one second", func(t *testing.T) { printHandshake(time.Now().Add(time.Second * -1)) _, err := out.Read(bytes) - should.BeNil(t, err) + should.NotBeError(t, err) should.ContainSubstring(t, string(bytes), "1 second ago") should.BeNil(t, out.Close()) }) t.Run("one minute", func(t *testing.T) { out, err := os.Open(os.Stdout.Name()) - should.BeNil(t, err) + should.NotBeError(t, err) printHandshake(time.Now().Add(time.Second * -60)) _, err = out.Read(bytes) - should.BeNil(t, err) + should.NotBeError(t, err) should.ContainSubstring(t, string(bytes), "1 minute 0 seconds ago") should.BeNil(t, out.Close()) }) t.Run("hours", func(t *testing.T) { out, err := os.Open(os.Stdout.Name()) - should.BeNil(t, err) + should.NotBeError(t, err) printHandshake(time.Now().Add(time.Second * -3600)) _, err = out.Read(bytes) - should.BeNil(t, err) + should.NotBeError(t, err) should.ContainSubstring(t, string(bytes), "1 hour 0 minutes 0 seconds ago") should.BeNil(t, out.Close()) }) t.Run("multi", func(t *testing.T) { out, err := os.Open(os.Stdout.Name()) - should.BeNil(t, err) + should.NotBeError(t, err) printHandshake(time.Now().Add(time.Second * -7250)) _, err = out.Read(bytes) - should.BeNil(t, err) + should.NotBeError(t, err) should.ContainSubstring(t, string(bytes), "2 hours 0 minutes 50 seconds ago") should.BeNil(t, out.Close()) }) t.Run("now", func(t *testing.T) { out, err := os.Open(os.Stdout.Name()) - should.BeNil(t, err) + should.NotBeError(t, err) printHandshake(time.Now()) _, err = out.Read(bytes) - should.BeNil(t, err) + should.NotBeError(t, err) should.ContainSubstring(t, string(bytes), "never") should.BeNil(t, out.Close()) }) diff --git a/app/plexus-agent/cmd/version.go b/app/plexus-agent/cmd/version.go index fa8237d..8197dc8 100644 --- a/app/plexus-agent/cmd/version.go +++ b/app/plexus-agent/cmd/version.go @@ -26,7 +26,7 @@ import ( "github.com/spf13/cobra" ) -const version = "v0.3.0" +const version = "v0.4.0" // versionCmd represents the version command. var versionCmd = &cobra.Command{ @@ -40,7 +40,13 @@ var versionCmd = &cobra.Command{ cobra.CheckErr(err) response := plexus.VersionResponse{} // need longer timeout is case of server timeout - err = agent.Request(nc, agent.Agent+plexus.Version, long, &response, agent.NatsLongTimeout) + err = agent.Request( + nc, + agent.Agent+plexus.Version, + long, + &response, + agent.NatsLongTimeout, + ) if err != nil { fmt.Println("error", err) } @@ -71,5 +77,6 @@ func init() { // Cobra supports local flags which will only run when this command // is called directly, e.g.: - versionCmd.Flags().BoolVarP(&long, "long", "l", false, "display server(s)/agent version information") + versionCmd.Flags(). + BoolVarP(&long, "long", "l", false, "display server(s)/agent version information") } diff --git a/docs/agent.md b/docs/agent.md index e369708..fe5a2fc 100644 --- a/docs/agent.md +++ b/docs/agent.md @@ -25,8 +25,8 @@ Available Commands: version display version information Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) -h, --help help for plexus-agent + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") Use "plexus-agent [command] --help" for more information about a command. @@ -48,7 +48,7 @@ Flags: -h, --help help for register Global Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") ``` @@ -65,7 +65,7 @@ Flags: -h, --help help for drop Global Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") ``` @@ -82,7 +82,7 @@ Flags: -h, --help help for join Global Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") ``` @@ -97,7 +97,7 @@ Flags: -h, --help help for leave Global Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") Leave command deletes current network on peer ``` @@ -157,7 +157,7 @@ Flags: -h, --help help for reload Global Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") ``` @@ -174,7 +174,7 @@ Flags: -h, --help help for reset Global Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") ``` @@ -215,7 +215,7 @@ Flags: -h, --help help for loglevel Global Flags: - --config string config file (default is /etc/plexus/plexus-agent.yaml) + -p, --natsport int nats port for cli <-> agent comms (default 4223) -v, --verbosity string logging verbosity (default "INFO") ``` diff --git a/docs/configuration.md b/docs/configuration.md index 7ef2ade..2000eb8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,27 +1,16 @@ Configuration ============= -Order of precedence -1. Environment variable with prefix of PLEXUS_ -2. Configuration variables in file /etc/plexus/config.yml -3. Default values Server ------ -| Variable | Env | Default | Usage | -| --- | ---- | ---- | --- | -| adminname | PLEXUS_ADMINNAME | admin | default admin username | -| adminpass | PLEXUS_ADMINPASS | password | password for default admin | -| verbosity | PLEXUS_VERBOSITY | info | level for logs | -| secure | PLEXUS_SECURE | true | use TLS for http and nats | -| port | PLEXUS_PORT | 8080 | web listen port when secure is false | -| email | PLEXUS_EMAIL | | email for use with Let's Encrypt | +| Variable | Default | Usage | +| --- | ---- | --- | +| adminname | admin | default admin username | +| adminpass | password | password for default admin | +| verbosity | info | level for logs | +| secure | true | use TLS for http and nats | +| port | | 8080 | web listen port when secure is false | +| email | | email for use with Let's Encrypt | * adminname/adminpass is only used to create a default user iff an admin user does not exist on server startup - -Agent ------ -| Variable | Env | Default | Usage | -| --- | ---- | ---- | --- | -| verbosity | PLEXUS_VERBOSITY | info | level for logs | -| natsport | PLEXUS_NATSPORT | 4223 | port for cli <-> agent nats comms | \ No newline at end of file diff --git a/docs/toc.md b/docs/index.md similarity index 100% rename from docs/toc.md rename to docs/index.md diff --git a/docs/install.md b/docs/install.md index 6e80bc6..c8d289d 100644 --- a/docs/install.md +++ b/docs/install.md @@ -50,4 +50,4 @@ If the server is to be installed behind a reverse proxy or in a lan only setting * set secure = false * set port (default 8080) to desired listening port for web traffic * fqdn must be set (can be an IP address) such that all peers can resolve the address of the server -> setting fqdn to an IP address in not valid with secure=true. Let's Encrypt does not support certificates for [IP addresses](https://community.letsencrypt.org/t/ssl-on-a-ip-instead-of-domain/90635) +> setting fqdn to an IP address is not valid with secure=true. Let's Encrypt does not support certificates for [IP addresses](https://community.letsencrypt.org/t/ssl-on-a-ip-instead-of-domain/90635) diff --git a/docs/screenshots/about.png b/docs/screenshots/about.png index 94c75b9..3181560 100644 Binary files a/docs/screenshots/about.png and b/docs/screenshots/about.png differ diff --git a/go.mod b/go.mod index c379a7e..9ee27ff 100644 --- a/go.mod +++ b/go.mod @@ -7,18 +7,19 @@ require ( github.com/c-robinson/iplib v1.0.8 github.com/caddyserver/certmagic v0.25.0 github.com/devilcove/boltdb v0.1.7 + github.com/devilcove/configuration v0.1.0 + github.com/devilcove/mux v0.2.1 github.com/fatih/color v1.18.0 - github.com/gin-contrib/sessions v1.0.4 - github.com/gin-gonic/gin v1.11.0 github.com/google/nftables v0.3.0 + github.com/gorilla/sessions v1.4.0 github.com/kr/pretty v0.3.1 github.com/lmittmann/tint v1.1.2 - github.com/nats-io/nats-server/v2 v2.12.2 - github.com/nats-io/nats.go v1.47.0 + github.com/mattkasun/tools v0.2.3 + github.com/nats-io/nats-server/v2 v2.12.3 + github.com/nats-io/nats.go v1.48.0 github.com/nats-io/nkeys v0.4.12 github.com/pion/stun v0.6.1 github.com/spf13/cobra v1.10.2 - github.com/spf13/viper v1.21.0 github.com/vishvananda/netlink v1.3.1 go.etcd.io/bbolt v1.4.3 golang.org/x/crypto v0.46.0 @@ -26,31 +27,15 @@ require ( ) require ( - github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op // indirect - github.com/bytedance/sonic v1.14.0 // indirect - github.com/bytedance/sonic/loader v0.3.0 // indirect + github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op // indirect github.com/caddyserver/zerossl v0.1.3 // indirect - github.com/cloudwego/base64x v0.1.6 // indirect - github.com/fsnotify/fsnotify v1.9.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.8 // indirect - github.com/gin-contrib/sse v1.1.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.27.0 // indirect - github.com/go-viper/mapstructure/v2 v2.4.0 // indirect - github.com/goccy/go-json v0.10.5 // indirect - github.com/goccy/go-yaml v1.18.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/go-tpm v0.9.6 // indirect - github.com/gorilla/context v1.1.2 // indirect + github.com/google/go-tpm v0.9.7 // indirect github.com/gorilla/securecookie v1.1.2 // indirect - github.com/gorilla/sessions v1.4.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.18.1 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/kr/text v0.2.0 // indirect - github.com/leodido/go-urn v1.4.0 // indirect github.com/libdns/libdns v1.1.1 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -60,32 +45,20 @@ require ( github.com/mholt/acmez/v3 v3.1.3 // indirect github.com/miekg/dns v1.1.68 // indirect github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nats-io/jwt/v2 v2.8.0 // indirect github.com/nats-io/nuid v1.0.1 // indirect - github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pion/dtls/v2 v2.2.7 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/transport/v2 v2.2.1 // indirect - github.com/quic-go/qpack v0.6.0 // indirect - github.com/quic-go/quic-go v0.57.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect - github.com/sagikazarmark/locafero v0.11.0 // indirect - github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect - github.com/spf13/afero v1.15.0 // indirect - github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect - github.com/subosito/gotenv v1.6.0 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.3.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect github.com/vishvananda/netns v0.0.5 // indirect github.com/zeebo/blake3 v0.2.4 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.uber.org/zap/exp v0.3.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/arch v0.20.0 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect golang.org/x/mod v0.30.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sync v0.19.0 // indirect @@ -94,5 +67,4 @@ require ( golang.org/x/time v0.14.0 // indirect golang.org/x/tools v0.39.0 // indirect golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect - google.golang.org/protobuf v1.36.9 // indirect ) diff --git a/go.sum b/go.sum index debbeb5..de9baf4 100644 --- a/go.sum +++ b/go.sum @@ -1,19 +1,13 @@ github.com/Kairum-Labs/should v0.2.2 h1:bO1kaMGRYRSSpq8MHsmk2MqpA1taLPblPCZy9Jnpt+U= github.com/Kairum-Labs/should v0.2.2/go.mod h1:vP/ASEjUAKoWy/M7uIrAXq69p7/IUWOpEe5R+q/+K34= -github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op h1:+OSa/t11TFhqfrX0EOSqQBDJ0YlpmK0rDSiB19dg9M0= -github.com/antithesishq/antithesis-sdk-go v0.4.3-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= -github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ= -github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA= -github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA= -github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op h1:Ucf+QxEKMbPogRO5guBNe5cgd9uZgfoJLOYs8WWhtjM= +github.com/antithesishq/antithesis-sdk-go v0.5.0-default-no-op/go.mod h1:IUpT2DPAKh6i/YhSbt6Gl3v2yvUZjmKncl7U91fup7E= github.com/c-robinson/iplib v1.0.8 h1:exDRViDyL9UBLcfmlxxkY5odWX5092nPsQIykHXhIn4= github.com/c-robinson/iplib v1.0.8/go.mod h1:i3LuuFL1hRT5gFpBRnEydzw8R6yhGkF4szNDIbF8pgo= github.com/caddyserver/certmagic v0.25.0 h1:VMleO/XA48gEWes5l+Fh6tRWo9bHkhwAEhx63i+F5ic= github.com/caddyserver/certmagic v0.25.0/go.mod h1:m9yB7Mud24OQbPHOiipAoyKPn9pKHhpSJxXR1jydBxA= github.com/caddyserver/zerossl v0.1.3 h1:onS+pxp3M8HnHpN5MMbOMyNjmTheJyWRaZYwn+YTAyA= github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/XofZnrYwGqG4= -github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= -github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -21,67 +15,40 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/devilcove/boltdb v0.1.7 h1:JVj8aZ/bilaGhduq1+E4qlWRrxYeH5sIjWdrdnBcsr0= github.com/devilcove/boltdb v0.1.7/go.mod h1:aXkamUgsGOC3njIPiZ/FzsYqAGGEMQyc5EE1gRHlOuw= +github.com/devilcove/configuration v0.1.0 h1:Aih99HhJ5lyf8fzjJagQmhjlkjyo3P36Wpr20NnCpI8= +github.com/devilcove/configuration v0.1.0/go.mod h1:T0EvOgFp4QGf5zVcV2kY78ghkRQnFiF/HPXzV5wMcSQ= +github.com/devilcove/mux v0.2.1 h1:V9Zu+aXxrmiFqligpgdWSmWYZ8XKYYtOwPrsxyKehI4= +github.com/devilcove/mux v0.2.1/go.mod h1:Q4ysJcjpLwW7rLNTOYSlYVst5OmwFh1uZxJSCPQ34U4= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= -github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= -github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM= -github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8= -github.com/gin-contrib/sessions v1.0.4 h1:ha6CNdpYiTOK/hTp05miJLbpTSNfOnFg5Jm2kbcqy8U= -github.com/gin-contrib/sessions v1.0.4/go.mod h1:ccmkrb2z6iU2osiAHZG3x3J4suJK+OU27oqzlWOqQgs= -github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= -github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= -github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk= -github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4= -github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= -github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= -github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= -github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= -github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-tpm v0.9.6 h1:Ku42PT4LmjDu1H5C5ISWLlpI1mj+Zq7sPGKoRw2XROA= -github.com/google/go-tpm v0.9.6/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= +github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/nftables v0.3.0 h1:bkyZ0cbpVeMHXOrtlFc8ISmfVqq5gPJukoYieyVmITg= github.com/google/nftables v0.3.0/go.mod h1:BCp9FsrbF1Fn/Yu6CLUc9GGZFw/+hsxfluNXXmxBfRM= -github.com/gorilla/context v1.1.2 h1:WRkNAv2uoa03QNIc1A6u4O7DAGMUVoopZhkiXWA2V1o= -github.com/gorilla/context v1.1.2/go.mod h1:KDPwT9i/MeWHiLl90fuTgrt4/wPcv75vFAZLaOOcbxM= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.4.0 h1:kpIYOp/oi6MG/p5PgxApU8srsSw9tuFbt46Lt7auzqQ= github.com/gorilla/sessions v1.4.0/go.mod h1:FLWm50oby91+hl7p/wRxDth9bWSuk0qVL2emc7lT5ik= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= -github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/libdns/libdns v1.1.1 h1:wPrHrXILoSHKWJKGd0EiAVmiJbFShguILTg9leS/P/U= github.com/libdns/libdns v1.1.1/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ= github.com/lmittmann/tint v1.1.2 h1:2CQzrL6rslrsyjqLDwD11bZ5OpLBPU+g3G/r5LSfS8w= github.com/lmittmann/tint v1.1.2/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= +github.com/mattkasun/tools v0.2.3 h1:g3ciN2dtA+NpTGqJvcuMaHy4NRkPKWt8TY8ZnJw8kVc= +github.com/mattkasun/tools v0.2.3/go.mod h1:WHhDjcX5n0ZAP0Z6XET1p2pCWqUgZDq8M5XEg+Pus9k= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -101,23 +68,16 @@ github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721 h1:RlZweED6sbSArvlE9 github.com/mikioh/ipaddr v0.0.0-20190404000644-d465c8ab6721/go.mod h1:Ickgr2WtCLZ2MDGd4Gr0geeCH5HybhRJbonOgQpvSxc= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76 h1:KGuD/pM2JpL9FAYvBrnBBeENKZNh6eNtjqytV6TYjnk= github.com/minio/highwayhash v1.0.4-0.20251030100505-070ab1a87a76/go.mod h1:GGYsuwP/fPD6Y9hMiXuapVvlIUEhFhMTh0rxU3ik1LQ= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/nats-io/jwt/v2 v2.8.0 h1:K7uzyz50+yGZDO5o772eRE7atlcSEENpL7P+b74JV1g= github.com/nats-io/jwt/v2 v2.8.0/go.mod h1:me11pOkwObtcBNR8AiMrUbtVOUGkqYjMQZ6jnSdVUIA= -github.com/nats-io/nats-server/v2 v2.12.2 h1:4TEQd0Y4zvcW0IsVxjlXnRso1hBkQl3TS0BI+SxgPhE= -github.com/nats-io/nats-server/v2 v2.12.2/go.mod h1:j1AAttYeu7WnvD8HLJ+WWKNMSyxsqmZ160pNtCQRMyE= -github.com/nats-io/nats.go v1.47.0 h1:YQdADw6J/UfGUd2Oy6tn4Hq6YHxCaJrVKayxxFqYrgM= -github.com/nats-io/nats.go v1.47.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= +github.com/nats-io/nats-server/v2 v2.12.3 h1:KRv+1n7lddMVgkJPQer+pt36TcO0ENxjilBmeWdjcHs= +github.com/nats-io/nats-server/v2 v2.12.3/go.mod h1:MQXjG9WjyXKz9koWzUc3jYUMKD8x3CLmTNy91IQQz3Y= +github.com/nats-io/nats.go v1.48.0 h1:pSFyXApG+yWU/TgbKCjmm5K4wrHu86231/w84qRVR+U= +github.com/nats-io/nats.go v1.48.0/go.mod h1:iRWIPokVIFbVijxuMQq4y9ttaBTMe0SFdlZfMDd+33g= github.com/nats-io/nkeys v0.4.12 h1:nssm7JKOG9/x4J8II47VWCL1Ds29avyiQDRn0ckMvDc= github.com/nats-io/nkeys v0.4.12/go.mod h1:MT59A1HYcjIcyQDJStTfaOY6vhy9XTUjOFo+SVsvpBg= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= -github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= @@ -129,46 +89,24 @@ github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1A github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= -github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= -github.com/quic-go/quic-go v0.57.0 h1:AsSSrrMs4qI/hLrKlTH/TGQeTMY0ib1pAOX7vA3AdqE= -github.com/quic-go/quic-go v0.57.0/go.mod h1:ly4QBAjHA2VhdnxhojRsCUOeJwKYg+taDlos92xb1+s= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= -github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= -github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= -github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= -github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= -github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= -github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= -github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA= -github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= github.com/vishvananda/netlink v1.3.1 h1:3AEMt62VKqz90r0tmNhog0r/PpWKmrEShJU0wJW6bV0= github.com/vishvananda/netlink v1.3.1/go.mod h1:ARtKouGSTGchR8aMwmkzC0qiNPrrWO5JS/XMVl45+b4= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= @@ -184,18 +122,15 @@ go.etcd.io/bbolt v1.4.3 h1:dEadXpI6G79deX5prL3QRNP6JB8UxVkqo4UPnHaNXJo= go.etcd.io/bbolt v1.4.3/go.mod h1:tKQlpPaYCVFctUIgFKFnAlvbmB3tpy1vkTnDWohtc0E= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.uber.org/zap/exp v0.3.0 h1:6JYzdifzYkGmTdRR59oYH+Ng7k49H9qVpWwNSsGJj3U= go.uber.org/zap/exp v0.3.0/go.mod h1:5I384qq7XGxYyByIhHm6jg5CHkGY0nsTfbDLgDDlgJQ= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c= -golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk= +go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go= +go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= @@ -255,11 +190,7 @@ golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 h1:/jFs0duh4rdb8uI golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173/go.mod h1:tkCQ4FQXmpAgYVh++1cq16/dH4QJtmvpRv19DWGAHSA= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10 h1:3GDAcqdIg1ozBNLgPy4SLT84nfcBjr6rhGtXYtrkWLU= golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10/go.mod h1:T97yPqesLiNrOYxkwmhMI0ZIlJDm+p0PMR8eRVeR5tQ= -google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= -google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/agent/broker.go b/internal/agent/broker.go index 4fa275b..549bf1b 100644 --- a/internal/agent/broker.go +++ b/internal/agent/broker.go @@ -20,7 +20,9 @@ import ( func startBroker() (*server.Server, *nats.Conn) { defer log.Println("Agent server halting") - ns, err := server.NewServer(&server.Options{Host: "localhost", Port: Config.NatsPort, NoSigs: true}) + ns, err := server.NewServer( + &server.Options{Host: "localhost", Port: Config.NatsPort, NoSigs: true}, + ) if err != nil { slog.Error("start nats", "error", err) panic(err) @@ -129,12 +131,15 @@ func subcribeToServerTopics(self Device) { } subscriptions = append(subscriptions, ping) - leaveServer, err := serverConn.Subscribe(plexus.Update+id+plexus.LeaveServer, func(_ *nats.Msg) { - slog.Info("leave server") - closeServerConnections() - deleteAllInterfaces() - deleteAllNetworks() - }) + leaveServer, err := serverConn.Subscribe( + plexus.Update+id+plexus.LeaveServer, + func(_ *nats.Msg) { + slog.Info("leave server") + closeServerConnections() + deleteAllInterfaces() + deleteAllNetworks() + }, + ) if err != nil { slog.Error("leave server subscription", "error", err) } @@ -271,7 +276,11 @@ func sendVersion(msg *nats.Msg, agentConn *nats.Conn) { slog.Error("version request", "error", err) } if err := json.Unmarshal(resp.Data, &response); err != nil { - slog.Error("invalid version response from server", "error", err, "data", string(resp.Data)) + slog.Error( + "invalid version response from server", + "error", err, + "data", string(resp.Data), + ) } } else { slog.Debug("not connected to server") diff --git a/internal/agent/config.go b/internal/agent/config.go index 2c2df45..f9d7553 100644 --- a/internal/agent/config.go +++ b/internal/agent/config.go @@ -19,10 +19,9 @@ const ( connectivityTimeout = time.Minute * 3 endpointServerTimeout = time.Second * 30 networkNotMapped = "network not mapped to server" - version = "v0.2.3" + version = "v0.4.0" networkTable = "networks" deviceTable = "devices" - path = "/var/lib/plexus/" ) var ( @@ -37,4 +36,5 @@ var ( type Configuration struct { NatsPort int Verbosity string + DataDir string } diff --git a/internal/agent/daemon.go b/internal/agent/daemon.go index 0fa9c58..37e834c 100644 --- a/internal/agent/daemon.go +++ b/internal/agent/daemon.go @@ -22,7 +22,7 @@ var restartEndpointServer chan struct{} func Run() { plexus.SetLogging(Config.Verbosity) - if err := boltdb.Initialize(path+"plexus-agent.db", []string{deviceTable, networkTable}); err != nil { + if err := boltdb.Initialize(Config.DataDir+"plexus-agent.db", []string{deviceTable, networkTable}); err != nil { slog.Error("failed to initialize database", "error", err) return } @@ -158,8 +158,15 @@ func privateEndpointServer(ctx context.Context, wg *sync.WaitGroup) { if me.PrivateEndpoint == nil { continue } - slog.Info("tcp listener starting on private endpoint", "endpoint", me.PrivateEndpoint, "port", me.ListenPort) - listener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: me.PrivateEndpoint, Port: me.ListenPort}) + slog.Info( + "tcp listener starting on private endpoint", + "endpoint", me.PrivateEndpoint, + "port", me.ListenPort, + ) + listener, err := net.ListenTCP( + "tcp", + &net.TCPAddr{IP: me.PrivateEndpoint, Port: me.ListenPort}, + ) if err != nil { slog.Error("public endpoint server", "error", err) return diff --git a/internal/agent/handlers.go b/internal/agent/handlers.go index bd6a682..6cc8607 100644 --- a/internal/agent/handlers.go +++ b/internal/agent/handlers.go @@ -20,7 +20,12 @@ func networkUpdates(msg *nats.Msg) { slog.Error("invalid network update", "error", err, "data", string(msg.Data)) return } - slog.Info("network update for", "network", networkName, "action", update.Action, "peer", update.Peer) + slog.Info( + "network update for", + "network", networkName, + "action", update.Action, + "peer", update.Peer, + ) network, err := boltdb.Get[Network](networkName, networkTable) if err != nil { if errors.Is(err, boltdb.ErrNoResults) { @@ -215,8 +220,12 @@ func processAddPeer(network Network, update *plexus.NetworkUpdate, wg *plexus.Wi slog.Debug("add peer") for _, peer := range network.Peers { if peer.WGPublicKey == update.Peer.WGPublicKey { - slog.Error("peer already exists", "network", network.Name, "peer", update.Peer.HostName, "id", - update.Peer.WGPublicKey) + slog.Error( + "peer already exists", + "network", network.Name, + "peer", update.Peer.HostName, + "id", update.Peer.WGPublicKey, + ) return } } @@ -241,7 +250,12 @@ func processAddPeer(network Network, update *plexus.NetworkUpdate, wg *plexus.Wi } } -func processDeletePeer(network Network, update *plexus.NetworkUpdate, self Device, wg *plexus.Wireguard) { +func processDeletePeer( + network Network, + update *plexus.NetworkUpdate, + self Device, + wg *plexus.Wireguard, +) { slog.Debug("delete peer") if update.Peer.WGPublicKey == self.WGPublicKey { slog.Info("self delete --> delete network", "network", network.Name) @@ -428,7 +442,11 @@ func sendListenPorts(msg *nats.Msg, serverConn *nats.Conn) { if err := serverConn.Publish(msg.Reply, bytes); err != nil { slog.Error("publish reply to SendListenPorts", "error", err) } - slog.Debug("sent listenports to server", "public", response.PublicListenPort, "private", response.ListenPort) + slog.Debug( + "sent listenports to server", + "public", response.PublicListenPort, + "private", response.ListenPort, + ) } func joinNetwork(msg *nats.Msg, self Device) { @@ -443,7 +461,12 @@ func joinNetwork(msg *nats.Msg, self Device) { return } if err := startInterface(self, network); err != nil { - slog.Error("error starting interface", "interface", network.Interface, "network", network.Name, "error", err) + slog.Error( + "error starting interface", + "interface", network.Interface, + "network", network.Name, + "error", err, + ) return } } diff --git a/internal/agent/interface.go b/internal/agent/interface.go index 0764e60..74298fd 100644 --- a/internal/agent/interface.go +++ b/internal/agent/interface.go @@ -62,7 +62,12 @@ func startAllInterfaces(self Device) { for _, network := range networks { slog.Debug("starting interface", "interface", network.Interface, "network", network.Name) if err := startInterface(self, network); err != nil { - slog.Error("start interface", "network", network.Name, "interface", network.Interface, "error", err) + slog.Error( + "start interface", + "network", network.Name, + "interface", network.Interface, + "error", err, + ) } } } @@ -81,7 +86,7 @@ func startInterface(self Device, network Network) error { } } if address.IPNet == nil { - return errors.New("no address for network" + network.Name) + return errors.New("no address for network " + network.Name) } privKey, err := wgtypes.ParseKey(self.WGPrivateKey) if err != nil { @@ -114,7 +119,10 @@ func startInterface(self Device, network Network) error { network.ListenPort = port } if addressChanged { - slog.Debug("public address changed ... saving and publishing update", "address", self.Endpoint) + slog.Debug( + "public address changed ... saving and publishing update", + "address", self.Endpoint, + ) if err := boltdb.Save(self, "self", deviceTable); err != nil { return err } @@ -232,7 +240,12 @@ func getAllowedIPs(node plexus.NetworkPeer, peers []plexus.NetworkPeer) []net.IP } else { allowed = append(allowed, node.Subnet) } - slog.Debug("new allowed ips", "allowed", allowed, "virt", node.VirtSubnet, "subnet", node.Subnet) + slog.Debug( + "new allowed ips", + "allowed", allowed, + "virt", node.VirtSubnet, + "subnet", node.Subnet, + ) } if node.IsRelay { for _, peer := range peers { @@ -250,7 +263,12 @@ func getWGPeers(self Device, network Network) []wgtypes.PeerConfig { keepalive := defaultKeepalive peers := []wgtypes.PeerConfig{} for _, peer := range network.Peers { - slog.Debug("checking peer", "peer", peer.WGPublicKey, "address", peer.Address, "mask", network.Net.Mask) + slog.Debug( + "checking peer", + "peer", peer.WGPublicKey, + "address", peer.Address, + "mask", network.Net.Mask, + ) if peer.WGPublicKey == self.WGPublicKey { if peer.IsRelayed { slog.Info("I am relayed") @@ -381,7 +399,10 @@ func getNewListenPorts(name string) (plexus.NetworkPeer, error) { }, nil } -func convertPeerToWG(netPeer plexus.NetworkPeer, peers []plexus.NetworkPeer) (wgtypes.PeerConfig, error) { +func convertPeerToWG( + netPeer plexus.NetworkPeer, + peers []plexus.NetworkPeer, +) (wgtypes.PeerConfig, error) { var addr *net.UDPAddr keepalive := defaultKeepalive key, err := wgtypes.ParseKey(netPeer.WGPublicKey) @@ -389,7 +410,10 @@ func convertPeerToWG(netPeer plexus.NetworkPeer, peers []plexus.NetworkPeer) (wg return wgtypes.PeerConfig{}, err } if netPeer.UsePrivateEndpoint { - addr, err = net.ResolveUDPAddr("udp", netPeer.PrivateEndpoint.String()+":"+strconv.Itoa(netPeer.ListenPort)) + addr, err = net.ResolveUDPAddr( + "udp", + netPeer.PrivateEndpoint.String()+":"+strconv.Itoa(netPeer.ListenPort), + ) if err != nil { return wgtypes.PeerConfig{}, err } diff --git a/internal/agent/interface_test.go b/internal/agent/interface_test.go new file mode 100644 index 0000000..2a0434e --- /dev/null +++ b/internal/agent/interface_test.go @@ -0,0 +1,36 @@ +package agent + +import ( + "os/user" + "testing" + + "github.com/Kairum-Labs/should" + "github.com/vishvananda/netlink" +) + +func TestInterface(t *testing.T) { + user, err := user.Current() + should.NotBeError(t, err) + if user.Uid != "0" { + t.Log("this test must be run as root") + t.Skip() + } + deleteAllNetworks() + deleteAllInterfaces() + nets := createTestSeverNetworks(t) + self, err := newDevice() + should.NotBeError(t, err) + should.NotBeError(t, saveServerNetworks(self, nets)) + + t.Run("startAll", func(t *testing.T) { + self, err := newDevice() + should.NotBeError(t, err) + ifaces, err := netlink.LinkList() + should.NotBeError(t, err) + number := len(ifaces) + startAllInterfaces(self) + ifaces, err = netlink.LinkList() + should.NotBeError(t, err) + should.BeEqual(t, len(ifaces), number+2) + }) +} diff --git a/internal/agent/join_test.go b/internal/agent/join_test.go index e18fd6d..cce89be 100644 --- a/internal/agent/join_test.go +++ b/internal/agent/join_test.go @@ -12,63 +12,61 @@ import ( func TestCheckPort(t *testing.T) { add := net.UDPAddr{ - Port: 51820, + Port: 51830, } conn, err := net.ListenUDP("udp", &add) - should.BeNil(t, err) + should.NotBeError(t, err) should.NotBeNil(t, conn) t.Run("portnotavail", func(t *testing.T) { - newPort := checkPort(51820) - should.BeEqual(t, newPort, 51821) + newPort := checkPort(51830) + should.BeEqual(t, newPort, 51831) }) err = conn.Close() - should.BeNil(t, err) + should.NotBeError(t, err) t.Run("portavail", func(t *testing.T) { - newPort := checkPort(51820) - should.BeEqual(t, newPort, 51820) + newPort := checkPort(51830) + should.BeEqual(t, newPort, 51830) }) t.Run("noports", func(t *testing.T) { add1 := net.UDPAddr{ Port: 65534, } conn1, err := net.ListenUDP("udp", &add1) - should.BeNil(t, err) + should.NotBeError(t, err) add2 := net.UDPAddr{ Port: 65535, } conn2, err := net.ListenUDP("udp", &add2) - should.BeNil(t, err) + should.NotBeError(t, err) newPort := checkPort(65534) should.BeEqual(t, newPort, 0) err = conn1.Close() - should.BeNil(t, err) + should.NotBeError(t, err) err = conn2.Close() - should.BeNil(t, err) + should.NotBeError(t, err) }) } func TestNewDevice(t *testing.T) { - err := boltdb.Initialize("./test.db", []string{deviceTable}) - should.BeNil(t, err) + // err := boltdb.Initialize("./test.db", []string{deviceTable}) + // should.NotBeError(t, err) device := Device{} - err = boltdb.Delete[Device]("self", deviceTable) + err := boltdb.Delete[Device]("self", deviceTable) if err != nil && !errors.Is(err, boltdb.ErrNoResults) { t.Fail() } hostname, err := os.Hostname() - should.BeNil(t, err) + should.NotBeError(t, err) t.Run("newDevice", func(t *testing.T) { device, err = newDevice() - should.BeNil(t, err) + should.NotBeError(t, err) should.BeEqual(t, device.Name, hostname) }) t.Run("existingDevice", func(t *testing.T) { device, err = newDevice() - should.BeNil(t, err) + should.NotBeError(t, err) new, err := newDevice() - should.BeNil(t, err) + should.NotBeError(t, err) should.BeEqual(t, new.Seed, device.Seed) }) - err = boltdb.Close() - should.BeNil(t, err) } diff --git a/internal/agent/network_test.go b/internal/agent/network_test.go new file mode 100644 index 0000000..de6c2c8 --- /dev/null +++ b/internal/agent/network_test.go @@ -0,0 +1,29 @@ +package agent + +import ( + "testing" + + "github.com/Kairum-Labs/should" + "github.com/devilcove/boltdb" +) + +func TestSaveServerNetwork(t *testing.T) { + serverNet := createTestSeverNetworks(t) + net, err := saveServerNetwork(serverNet[0]) + should.BeNil(t, err) + should.BeEqual(t, net.Name, serverNet[0].Name) + dbNet, err := boltdb.Get[Network](net.Name, networkTable) + should.NotBeError(t, err) + should.BeEqual(t, dbNet.Name, serverNet[0].Name) +} + +func TestSaveServerNetworks(t *testing.T) { + deleteAllNetworks() + self, err := newDevice() + should.NotBeError(t, err) + serverNets := createTestSeverNetworks(t) + should.NotBeError(t, saveServerNetworks(self, serverNets)) + networks, err := boltdb.GetAll[Network](networkTable) + should.NotBeError(t, err) + should.BeEqual(t, len(networks), 2) +} diff --git a/internal/agent/nftables.go b/internal/agent/nftables.go index ce890b1..7d9dec8 100644 --- a/internal/agent/nftables.go +++ b/internal/agent/nftables.go @@ -74,7 +74,12 @@ func checkForNat(self Device, network Network) error { return addNat() } if peer.UseVirtSubnet { - slog.Debug("adding virtual subnet", "peer", peer.HostName, "virtual subnet", peer.VirtSubnet, "subnet", peer.Subnet) + slog.Debug( + "adding virtual subnet", + "peer", peer.HostName, + "virtual subnet", peer.VirtSubnet, + "subnet", peer.Subnet, + ) return addVirtualSubnet(peer.VirtSubnet, peer.Subnet) } } diff --git a/internal/agent/nftables_test.go b/internal/agent/nftables_test.go index e4fcaac..a78313a 100644 --- a/internal/agent/nftables_test.go +++ b/internal/agent/nftables_test.go @@ -15,16 +15,16 @@ func TestAddNAT(t *testing.T) { table := &nftables.Table{} chain := &nftables.Chain{} user, err := user.Current() - should.BeNil(t, err) + should.NotBeError(t, err) if user.Uid != "0" { t.Log("this test must be run as root") t.Skip() } c := nftables.Conn{} err = addNat() - should.BeNil(t, err) + should.NotBeError(t, err) tables, err := c.ListTables() - should.BeNil(t, err) + should.NotBeError(t, err) tableFound := false for _, t := range tables { if t.Name == "plexus" { @@ -34,7 +34,7 @@ func TestAddNAT(t *testing.T) { } should.BeTrue(t, tableFound) chains, err := c.ListChains() - should.BeNil(t, err) + should.NotBeError(t, err) chainFound := false for _, c := range chains { if c.Name == "plexus-nat" { @@ -44,7 +44,7 @@ func TestAddNAT(t *testing.T) { } should.BeTrue(t, chainFound) rules, err := c.GetRules(table, chain) - should.BeNil(t, err) + should.NotBeError(t, err) should.BeEqual(t, len(rules), 1) should.BeEqual(t, rules[0].Exprs[0], &expr.Masq{ Random: false, @@ -59,7 +59,7 @@ func TestAddNAT(t *testing.T) { func TestDelNat(t *testing.T) { user, err := user.Current() - should.BeNil(t, err) + should.NotBeError(t, err) if user.Uid != "0" { t.Log("this test must be run as root") t.Skip() @@ -85,11 +85,11 @@ func TestDelNat(t *testing.T) { } c.AddRule(rule) err = c.Flush() - should.BeNil(t, err) + should.NotBeError(t, err) err = delNat() - should.BeNil(t, err) + should.NotBeError(t, err) chains, err := c.ListChains() - should.BeNil(t, err) + should.NotBeError(t, err) found := false for _, chain := range chains { if chain.Name == "plexus-nat" { @@ -103,13 +103,13 @@ func TestDelNat(t *testing.T) { func TestCheckForNat(t *testing.T) { plexus.SetLogging("debug") user, err := user.Current() - should.BeNil(t, err) + should.NotBeError(t, err) if user.Uid != "0" { t.Log("this test must be run as root") t.Skip() } _, public, err := generateKeys() - should.BeNil(t, err) + should.NotBeError(t, err) self := Device{} self.WGPublicKey = public.String() peer := plexus.NetworkPeer{ @@ -125,19 +125,19 @@ func TestCheckForNat(t *testing.T) { network.Peers = append(network.Peers, peer) c := &nftables.Conn{} tables, err := c.ListTables() - should.BeNil(t, err) + should.NotBeError(t, err) for _, table := range tables { if table.Name == "plexus" { c.DelTable(table) err = c.Flush() - should.BeNil(t, err) + should.NotBeError(t, err) } } t.Run("noSubnetRouter", func(t *testing.T) { err := checkForNat(self, network) - should.BeNil(t, err) + should.NotBeError(t, err) tables, err := c.ListTables() - should.BeNil(t, err) + should.NotBeError(t, err) for _, table := range tables { if table.Name == "plexus" { t.FailNow() @@ -152,9 +152,9 @@ func TestCheckForNat(t *testing.T) { } network.Peers = []plexus.NetworkPeer{peer} err = checkForNat(self, network) - should.BeNil(t, err) + should.NotBeError(t, err) tables, err := c.ListTables() - should.BeNil(t, err) + should.NotBeError(t, err) for _, table := range tables { if table.Name == "plexus" { t.FailNow() @@ -167,9 +167,9 @@ func TestCheckForNat(t *testing.T) { peer.UseNat = true network.Peers = []plexus.NetworkPeer{peer} err = checkForNat(self, network) - should.BeNil(t, err) + should.NotBeError(t, err) tables, err := c.ListTables() - should.BeNil(t, err) + should.NotBeError(t, err) tableFound := false for _, t := range tables { if t.Name == "plexus" { @@ -179,7 +179,7 @@ func TestCheckForNat(t *testing.T) { } should.BeTrue(t, tableFound) chains, err := c.ListChains() - should.BeNil(t, err) + should.NotBeError(t, err) chainFound := false for _, c := range chains { if c.Name == "plexus-nat" { @@ -189,7 +189,7 @@ func TestCheckForNat(t *testing.T) { } should.BeTrue(t, chainFound) rules, err := c.GetRules(table, chain) - should.BeNil(t, err) + should.NotBeError(t, err) should.BeEqual(t, len(rules), 1) should.BeEqual(t, rules[0].Exprs[0], &expr.Masq{ Random: false, @@ -212,9 +212,9 @@ func TestCheckForNat(t *testing.T) { network.Peers = []plexus.NetworkPeer{peer} t.Log(self, network) err = checkForNat(self, network) - should.BeNil(t, err) + should.NotBeError(t, err) tables, err := c.ListTables() - should.BeNil(t, err) + should.NotBeError(t, err) tableFound := false for _, t := range tables { if t.Name == "plexus" { @@ -224,7 +224,7 @@ func TestCheckForNat(t *testing.T) { } should.BeTrue(t, tableFound) chains, err := c.ListChains() - should.BeNil(t, err) + should.NotBeError(t, err) chainFound := false for _, c := range chains { if c.Name == "plexus-subnet" { @@ -234,20 +234,21 @@ func TestCheckForNat(t *testing.T) { } should.BeTrue(t, chainFound) rules, err := c.GetRules(table, chain) - should.BeNil(t, err) + should.NotBeError(t, err) should.BeEqual(t, len(rules), 254) }) cleanNat(t, c) } func cleanNat(t *testing.T, c *nftables.Conn) { + t.Helper() tables, err := c.ListTables() - should.BeNil(t, err) + should.NotBeError(t, err) for _, table := range tables { if table.Name == "plexus" { c.DelTable(table) err := c.Flush() - should.BeNil(t, err) + should.NotBeError(t, err) break } } diff --git a/internal/agent/plexus_test.go b/internal/agent/plexus_test.go new file mode 100644 index 0000000..1644f8e --- /dev/null +++ b/internal/agent/plexus_test.go @@ -0,0 +1,71 @@ +package agent + +import ( + "log" + "net" + "os" + "testing" + + "github.com/Kairum-Labs/should" + "github.com/devilcove/boltdb" + "github.com/devilcove/plexus" +) + +func TestMain(m *testing.M) { + if _, err := os.Stat("./test.db"); err == nil { + if err := os.Remove("./test.db"); err != nil { + log.Println("remove db", err) + os.Exit(1) + } + } + if err := boltdb.Initialize("./test.db", + []string{deviceTable, networkTable}, + ); err != nil { + log.Println("init db", err) + os.Exit(2) + } + plexus.SetLogging("debug") + code := m.Run() + // cancel() + // wg.Wait() + boltdb.Close() + os.Exit(code) +} + +func createTestSeverNetworks(t *testing.T) []plexus.Network { + t.Helper() + self, err := newDevice() + should.NotBeError(t, err) + ip1, cidr1, err := net.ParseCIDR("10.100.0.2/24") + should.NotBeError(t, err) + ip2, cidr2, err := net.ParseCIDR("10.200.0.2/24") + should.NotBeError(t, err) + return []plexus.Network{ + { + Name: "one", + Net: *cidr1, + Peers: []plexus.NetworkPeer{ + { + WGPublicKey: self.WGPublicKey, + Address: net.IPNet{ + IP: ip1, + Mask: net.CIDRMask(32, 32), + }, + }, + }, + }, + { + Name: "two", + Net: *cidr2, + Peers: []plexus.NetworkPeer{ + { + WGPublicKey: self.WGPublicKey, + Address: net.IPNet{ + IP: ip2, + Mask: net.CIDRMask(32, 32), + }, + }, + }, + }, + } +} diff --git a/internal/agent/publish.go b/internal/agent/publish.go index 99591a2..e26d332 100644 --- a/internal/agent/publish.go +++ b/internal/agent/publish.go @@ -104,10 +104,13 @@ func checkin() { continue } if peer.PrivateEndpoint != nil { - checkinData.PrivateEndpoints = append(checkinData.PrivateEndpoints, plexus.PrivateEndpoint{ - IP: peer.PrivateEndpoint.String(), - Network: network.Name, - }) + checkinData.PrivateEndpoints = append( + checkinData.PrivateEndpoints, + plexus.PrivateEndpoint{ + IP: peer.PrivateEndpoint.String(), + Network: network.Name, + }, + ) } } } diff --git a/internal/agent/register.go b/internal/agent/register.go index b64f23a..b9b6808 100644 --- a/internal/agent/register.go +++ b/internal/agent/register.go @@ -94,11 +94,7 @@ func newDevice() (Device, error) { Seed: seed, WGPrivateKey: privKey.String(), } - if err := os.MkdirAll(path, os.ModePerm); err != nil { - slog.Error("unable to mkdir", "path", path, "error", err) - return device, err - } - if err := os.WriteFile(path+"agent.seed", []byte(seed), os.ModePerm); err != nil { + if err := os.WriteFile(Config.DataDir+"agent.seed", []byte(seed), os.ModePerm); err != nil { slog.Error("save seed", "error", err) } err = boltdb.Save(device, "self", deviceTable) diff --git a/internal/server/broker.go b/internal/server/broker.go index 22a3884..bbd90d0 100644 --- a/internal/server/broker.go +++ b/internal/server/broker.go @@ -11,6 +11,7 @@ import ( "time" "github.com/devilcove/boltdb" + "github.com/devilcove/configuration" "github.com/devilcove/plexus" "github.com/devilcove/plexus/internal/publish" "github.com/nats-io/nats-server/v2/server" @@ -49,6 +50,11 @@ func broker(ctx context.Context, wg *sync.WaitGroup, tls *tls.Config) { natsOptions.Nkeys = append(natsOptions.Nkeys, tokensUsers...) natsOptions.Nkeys = append(natsOptions.Nkeys, deviceUsers...) natsOptions.NoSigs = true + config := &Configuration{} + if err := configuration.Get(config); err != nil { + slog.Error("configuration", "error", err) + return + } if config.Secure { natsOptions.TLSConfig = tls natsOptions.Host = config.FQDN @@ -67,7 +73,7 @@ func broker(ctx context.Context, wg *sync.WaitGroup, tls *tls.Config) { return adminKey.Sign(nonce) } opts := []nats.Option{nats.Nkey(adminPublicKey, SignatureCB)} - natsConn, err = nats.Connect(net.JoinHostPort("nats://"+config.FQDN, "4222"), opts...) + natsConn, err = nats.Connect("nats://"+net.JoinHostPort(config.FQDN, "4222"), opts...) if err != nil { slog.Error("nats connect", "error", err) brokerfail <- 1 @@ -90,27 +96,6 @@ func startBroker(ctx context.Context) { _ = sub.Drain() } return - case token := <-newDevice: - slog.Info("new login device", "device", token) - keyValue, err := plexus.DecodeToken(token) - if err != nil { - slog.Error("decode token", "error", err) - } - key, err := nkeys.FromSeed([]byte(keyValue.Seed)) - if err != nil { - slog.Error("seed failure", "error", err) - continue - } - nPubKey, err := key.PublicKey() - if err != nil { - slog.Error("publickey", "error", err) - continue - } - natsOptions.Nkeys = append(natsOptions.Nkeys, &server.NkeyUser{ - Nkey: nPubKey, - Permissions: registerPermissions(), - }) - _ = natServer.ReloadOptions(natsOptions) case <-pingTicker.C: pingPeers() case <-keyTicker.C: @@ -153,7 +138,12 @@ func createNkeyUser(token string) *server.NkeyUser { } func getAdminKey() nkeys.KeyPair { - seed, err := os.ReadFile(path + "server.seed") + config := Configuration{} + if err := configuration.Get(&config); err != nil { + slog.Error("configuration", "error", err) + return nil + } + seed, err := os.ReadFile(config.DataHome + "server.seed") if err != nil { return createAdminNKeyPair() } @@ -176,7 +166,12 @@ func createAdminNKeyPair() nkeys.KeyPair { slog.Error("admin seed creation", "error", err) return admin } - if err := os.WriteFile(path+"server.seed", seed, os.ModePerm); err != nil { + config := Configuration{} + if err := configuration.Get(&config); err != nil { + slog.Error("configuration", "error", err) + return nil + } + if err := os.WriteFile(config.DataHome+"/server.seed", seed, os.ModePerm); err != nil { slog.Error("save admin seed", "error", err) } return admin diff --git a/internal/server/config.go b/internal/server/config.go index 6aae283..f1997a6 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -4,21 +4,21 @@ import ( "crypto/tls" "errors" "fmt" - "io/fs" "log/slog" "net" "net/mail" "os" + "path/filepath" "strings" "time" "github.com/caddyserver/certmagic" "github.com/devilcove/boltdb" + "github.com/devilcove/configuration" "github.com/devilcove/plexus" - "github.com/spf13/viper" ) -type configuration struct { +type Configuration struct { AdminName string AdminPass string FQDN string @@ -26,9 +26,8 @@ type configuration struct { Port string Email string Verbosity string - DBPath string + DataHome string DBFile string - Tables []string } const ( @@ -40,13 +39,14 @@ const ( ) var ( - config configuration - ErrServerURL = errors.New("invalid server URL") - ErrInvalidSubnet = errors.New("invalid subnet") - ErrSubnetInUse = errors.New("subnet in use") - sessionAge = 60 * 60 * 24 - version = "v0.2.3" - path = "/var/lib/plexus/" + ErrServerURL = errors.New("invalid server URL") + ErrInvalidSubnet = errors.New("invalid subnet") + ErrSubnetInUse = errors.New("subnet in use") + ErrDataDir = errors.New("data dir not found") + ErrSecureBlankFQDN = errors.New("secure server requires FQDN") + ErrSecureWithIP = errors.New("cannot use IP address with secure") + ErrInValidEmail = errors.New("valid email address required") + version = "v0.4.0" ) const ( @@ -59,44 +59,61 @@ const ( ) func configureServer() (*tls.Config, error) { - var tlsConfig *tls.Config - viper.SetDefault("adminname", "admin") - viper.SetDefault("adminpass", "password") - viper.SetDefault("verbosity", "INFO") - viper.SetDefault("secure", true) - viper.SetDefault("port", "8080") - viper.SetDefault("email", "") - viper.SetDefault("dbfile", "plexus-server.db") - viper.SetDefault("tables", []string{userTable, keyTable, networkTable, peerTable, settingTable}) - viper.SetDefault("dbpath", path) - viper.SetConfigFile("/etc/plexus/config") - viper.SetConfigType("yaml") - if err := viper.ReadInConfig(); err != nil && !errors.Is(err, fs.ErrNotExist) { + plexus.SetLogging("INFO") + home, err := os.UserHomeDir() + if err != nil { return nil, err } - viper.SetEnvPrefix("PLEXUS") - viper.AutomaticEnv() - if err := viper.UnmarshalExact(&config); err != nil { + config := Configuration{} + if err := configuration.Get(&config); err != nil { return nil, err } + // set defaults + if config.AdminName == "" { + config.AdminName = "admin" + } + if config.AdminPass == "" { + config.AdminPass = "password" + } + if config.Verbosity == "" { + config.Verbosity = "INFO" + } + if config.Port == "" { + config.Port = "8080" + } + if config.DBFile == "" { + config.DBFile = "plexus-server.db" + } + if config.DataHome == "" { + config.DataHome = home + "/.local/share/" + filepath.Base(os.Args[0]) + "/" + } + if _, err := os.Stat(config.DataHome); err != nil { + return nil, ErrDataDir + } + + slog.Info("configure Server", "config", config) + var tlsConfig *tls.Config plexus.SetLogging(config.Verbosity) if config.Secure { if config.FQDN == "" { - return nil, errors.New("secure server requires FQDN") + return nil, ErrSecureBlankFQDN } if net.ParseIP(config.FQDN) != nil { - return nil, errors.New("cannot use IP address with secure") + return nil, ErrSecureWithIP } if !emailValid(config.Email) { - return nil, errors.New("valid email address required") + return nil, ErrInValidEmail } } // initialize database. - if err := os.MkdirAll(config.DBPath, os.ModePerm); err != nil { + if err := os.MkdirAll(config.DataHome, os.ModePerm); err != nil { return nil, err } - slog.Info("init db", "path", config.DBFile, "file", config.DBFile, "tables", config.Tables) - if err := boltdb.Initialize(config.DBPath+config.DBFile, config.Tables); err != nil { + slog.Info("init db", "path", config.DataHome, "file", config.DBFile) + if err := boltdb.Initialize( + filepath.Join(config.DataHome, config.DBFile), + []string{"users", "keys", "networks", "peers", "settings"}, + ); err != nil { return nil, fmt.Errorf("init database %w", err) } // check default user exists. diff --git a/internal/server/config_test.go b/internal/server/config_test.go index 0aa8d97..9030964 100644 --- a/internal/server/config_test.go +++ b/internal/server/config_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/Kairum-Labs/should" + "github.com/devilcove/boltdb" ) func Test_emailValid(t *testing.T) { @@ -36,3 +37,45 @@ func Test_emailValid(t *testing.T) { }) } } + +func TestConfigureServer(t *testing.T) { + setup(t) + defer shutdown(t) + err := boltdb.Close() + should.NotBeError(t, err) + defer func() { + err := boltdb.Initialize("./test.db", + []string{userTable, keyTable, networkTable, peerTable, settingTable}) + should.NotBeError(t, err) + }() + + t.Run("secureNoFQDM", func(t *testing.T) { + writeTmpConfg(t, &Configuration{Secure: true, FQDN: ""}) + config, err := configureServer() + should.BeErrorIs(t, err, ErrSecureBlankFQDN) + should.BeNil(t, config) + }) + + t.Run("secureWithIP", func(t *testing.T) { + writeTmpConfg(t, &Configuration{Secure: true, FQDN: "10.10.10.100"}) + config, err := configureServer() + should.BeErrorIs(t, err, ErrSecureWithIP) + should.BeNil(t, config) + }) + + t.Run("secureNoEmail", func(t *testing.T) { + writeTmpConfg(t, &Configuration{Secure: true, FQDN: "example.com"}) + config, err := configureServer() + should.BeErrorIs(t, err, ErrInValidEmail) + should.BeNil(t, config) + }) + + t.Run("insecure", func(t *testing.T) { + writeTmpConfg(t, &Configuration{FQDN: "example.com", Email: "admin@domain.com"}) + config, err := configureServer() + should.NotBeError(t, err) + should.BeNil(t, config) + t.Log(err, config) + should.BeNil(t, boltdb.Close()) + }) +} diff --git a/internal/server/html/about.html b/internal/server/html/about.html index 2ac930b..0651c6b 100644 --- a/internal/server/html/about.html +++ b/internal/server/html/about.html @@ -3,15 +3,13 @@
- logo
+ logo
Version {{ .Version }} -

© 2023-2024 Matthew R. Kasun

+

© 2023-2026 Matthew R. Kasun

built with go - gin nats bbolt - w3css and htmx

@@ -20,7 +18,8 @@

© 2023-2024 Matthew R. Kasun

repo


- +
diff --git a/internal/server/html/content.html b/internal/server/html/content.html index 03c45d6..207eed2 100644 --- a/internal/server/html/content.html +++ b/internal/server/html/content.html @@ -1,25 +1,21 @@ {{define "content"}} {{if (eq .NeedsLogin true)}} {{template "login" .}} -{{ else if (eq .Page "addNetwork")}} -{{template "addNetwork"}} -{{ else if (eq .Page "networks")}} -{{template "networks" . }} -{{ else if (eq .Page "peers")}} -{{template "peers" . }} -{{ else if (eq .Page "keys")}} -{{template "keys" . }} -{{ else if (eq .Page "users")}} -{{template "users" . }} -{{ else if (eq .Page "settings")}} -{{template "settings" . }} + {{ else }} -
-
-
-
-
- {{template "sidebar" .Networks}} +{{template "sidebar" .Networks}} +
+ {{ if (eq .Page "addNetwork")}} + {{template "addNetwork"}} + {{ else if (eq .Page "networks")}} + {{template "networks" . }} + {{ else if (eq .Page "peers")}} + {{template "peers" . }} + {{ else if (eq .Page "keys")}} + {{template "keys" . }} + {{ else if (eq .Page "users")}} + {{template "users" . }} + {{end}}
{{end}} {{end}} \ No newline at end of file diff --git a/internal/server/html/error.html b/internal/server/html/error.html index 375aeac..cdcf438 100644 --- a/internal/server/html/error.html +++ b/internal/server/html/error.html @@ -1,3 +1,13 @@ {{define "error"}} -

Error Processing Request: {{ . }}

+
+
+
+ logo
+

Error Processing Request: {{ . }}

+

+ +
+
+
{{end}} \ No newline at end of file diff --git a/internal/server/html/header.html b/internal/server/html/header.html index 0c316e2..36262a4 100644 --- a/internal/server/html/header.html +++ b/internal/server/html/header.html @@ -1,12 +1,12 @@ {{define "header"}}
- - Plexus -
-
- User - Logout -
-
+ + Plexus +
+
+ User + Logout +
+
-{{end}} +{{end}} \ No newline at end of file diff --git a/internal/server/html/keys.html b/internal/server/html/keys.html index 38a7c5e..969bcf0 100644 --- a/internal/server/html/keys.html +++ b/internal/server/html/keys.html @@ -1,8 +1,7 @@ {{define "keys"}} -
+
@@ -20,7 +19,7 @@

Networks

Delete
{{range .Data}}
- @@ -38,7 +37,6 @@

Networks

{{end}} {{ define "addNetwork"}} -

Add Network

@@ -46,7 +44,7 @@

Add Network


- @@ -55,8 +53,7 @@

Add Network

{{end}} {{define "networkDetails"}} -
+
@@ -81,8 +78,8 @@

Peers

{{range .Peers}}
-
@@ -117,13 +114,12 @@

Peers

hx-target="#content" hx-target-error="#error" hx-confirm="Remove Relay from Network?"> Delete Relay -
+
{{else if eq .IsRelayed true}} -
Relayed
+
Relayed
{{else}}
- diff --git a/internal/server/html/peers.html b/internal/server/html/peers.html index e43e0bd..491a7b1 100644 --- a/internal/server/html/peers.html +++ b/internal/server/html/peers.html @@ -1,7 +1,7 @@ {{define "peers"}} -
+

Peers

@@ -27,8 +27,7 @@

Peers

{{end}} {{define "peerDetails"}} -
+

Peer: {{.Name}}

Wireguard Public Key
@@ -49,7 +48,6 @@

Peer: {{.Name}}

{{end}} {{define "displayNetworkPeer"}} -

Network Peer: {{.HostName}}

Wireguard Public Key
@@ -73,14 +71,14 @@

Network Peer: {{.HostName}}

Is Subnet Router
{{.IsSubnetRouter}}
{{if eq .IsSubnetRouter true}} -
Subnet
-
{{.Subnet}}
-
Use Nat
-
{{.UseNat}}
- {{if eq .UseVirtSubnet true}} -
Virtual Subnet
-
{{.VirtSubnet}}
- {{end}} +
Subnet
+
{{.Subnet}}
+
Use Nat
+
{{.UseNat}}
+ {{if eq .UseVirtSubnet true}} +
Virtual Subnet
+
{{.VirtSubnet}}
+ {{end}} {{end}} {{if eq .IsSubnetRouter}}
diff --git a/internal/server/html/relay.html b/internal/server/html/relay.html index 885db65..f985aab 100644 --- a/internal/server/html/relay.html +++ b/internal/server/html/relay.html @@ -1,5 +1,4 @@ {{define "addRelayToNetwork"}} -

Network {{.Network}}

Create Relay

Peers to Relay

@@ -10,8 +9,8 @@

Peers to Relay

{{end}}

- diff --git a/internal/server/html/router.html b/internal/server/html/router.html index a07119c..1fe898e 100644 --- a/internal/server/html/router.html +++ b/internal/server/html/router.html @@ -1,10 +1,9 @@ {{define "addRouterToNetwork"}} -

Network: {{.Network}}

Create Subnet Router

- +

Nat

@@ -14,14 +13,14 @@

Nat


-

- diff --git a/internal/server/html/server.html b/internal/server/html/server.html index 206875f..2bf4ef9 100644 --- a/internal/server/html/server.html +++ b/internal/server/html/server.html @@ -1,14 +1,16 @@ {{define "server"}} -

+

Server Logs

Current Log Level: {{.LogLevel}}

{{range .Logs}} diff --git a/internal/server/html/sidebar.html b/internal/server/html/sidebar.html index 0c622e7..2aef480 100644 --- a/internal/server/html/sidebar.html +++ b/internal/server/html/sidebar.html @@ -9,8 +9,8 @@ Networks {{range .}} - {{end}} @@ -47,11 +47,11 @@
HOME + hx-target="#home">ABOUT + hx-target="#home">PROJECTS + hx-target="#home">CONTACT
{{end}} @@ -62,8 +62,8 @@ Networks {{range .}} - {{end}} diff --git a/internal/server/html/users.html b/internal/server/html/users.html index 6ea85c8..fc105aa 100644 --- a/internal/server/html/users.html +++ b/internal/server/html/users.html @@ -1,6 +1,6 @@ {{define "users"}} -
+
@@ -27,7 +27,6 @@

Authorized Users

{{end}} {{define "editUser"}} -

@@ -35,7 +34,7 @@

Edit User

{{.Username}}

-
+


@@ -43,7 +42,7 @@

{{.Username}}