diff --git a/Dockerfile b/Dockerfile index 4928ddb..6f17f19 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ COPY ./ ./ RUN set -eux; \ apk add --no-cache bash make git protoc protobuf-dev dumb-init mailcap ca-certificates tzdata; \ update-ca-certificates; \ - make install_protobuf build + make generate build FROM scratch WORKDIR / diff --git a/Makefile b/Makefile index ba0e127..14d2f5f 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ LDFLAGS="-X 'github.com/Neur0toxine/sshpoke/cmd.Version=${VERSION}'" .PHONY: run clean_backend clone_sshlib -build: generate deps fmt +build: deps fmt @echo " ► Building with ${GO_VERSION}" @CGO_ENABLED=0 go build -tags=release -ldflags ${LDFLAGS} -o $(BIN) . @echo $(BIN) @@ -34,13 +34,25 @@ run: clean: @rm -rf $(BUILD_DIR) -generate: +generate: install_swag install_protobuf @echo " ► Performing code generation" - @cd $(ROOT_DIR)/pkg/plugin && go generate + @cd $(ROOT_DIR) && go generate `go list -f '{{.Dir}}' ${ROOT_DIR}/... | grep -v /vendor/` install_protobuf: +ifeq (, $(shell command -v protoc-gen-go 2> /dev/null)) + @echo " ► Installing protoc-gen-go" @go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28 +endif +ifeq (, $(shell command -v protoc-gen-go-grpc 2> /dev/null)) + @echo " ► Installing protoc-gen-go-grpc" @go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2 +endif + +install_swag: +ifeq (, $(shell command -v swag 2> /dev/null)) + @echo " ► Installing swag tool" + @go install github.com/swaggo/swag/cmd/swag@latest +endif clone_cryptolib: @rm -rf cryptolib && \ diff --git a/cmd/root.go b/cmd/root.go index 79cfd5e..cb9406e 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,7 +7,7 @@ import ( "syscall" "github.com/Neur0toxine/sshpoke/internal/api/plugin" - "github.com/Neur0toxine/sshpoke/internal/api/web" + "github.com/Neur0toxine/sshpoke/internal/api/rest" "github.com/Neur0toxine/sshpoke/internal/config" "github.com/Neur0toxine/sshpoke/internal/docker" "github.com/Neur0toxine/sshpoke/internal/logger" @@ -33,7 +33,7 @@ var rootCmd = &cobra.Command{ ctx, cancel := context.WithCancel(context.Background()) server.DefaultManager = server.NewManager(ctx, config.Default.Servers, config.Default.DefaultServer) runPluginServer() - runWebServer() + runRestServer() runDockerEventListener(ctx) shutdown := makeShutdownFunc(cancel) @@ -88,8 +88,8 @@ func initConfig() { if err := validator.New().Struct(config.Default); err != nil { log.Fatalf("invalid configuration: %s", err) } - if config.Default.API.Web.Port == 0 { - config.Default.API.Web.Port = web.DefaultPort + if config.Default.API.Rest.Port == 0 { + config.Default.API.Rest.Port = rest.DefaultPort } if config.Default.API.Plugin.Port == 0 { config.Default.API.Plugin.Port = plugin2.DefaultPort @@ -106,13 +106,13 @@ func runPluginServer() { go plugin.StartServer(port, logger.Sugar.With("component", "pluginServer")) } -func runWebServer() { - port := config.Default.API.Web.Port +func runRestServer() { + port := config.Default.API.Rest.Port if port == 0 { - port = web.DefaultPort + port = rest.DefaultPort } - go web.StartServer( - config.Default.API.Web.Token, port, logger.Sugar.With("component", "webServer"), config.Default.Debug) + go rest.StartServer( + config.Default.API.Rest.Token, port, logger.Sugar.With("component", "webServer"), config.Default.Debug) } func runDockerEventListener(ctx context.Context) { diff --git a/examples/config.yml b/examples/config.yml index 5d0e20c..bced228 100644 --- a/examples/config.yml +++ b/examples/config.yml @@ -2,8 +2,8 @@ debug: true # API settings. api: - web: - # Local port for Web API. Will be bound to localhost. + rest: + # Local port for REST API. Will be bound to localhost. port: 25680 token: "VbNG6T6wYmj9YHM6etuZgN35" plugin: diff --git a/go.mod b/go.mod index b5a5851..5fa5d08 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,9 @@ require ( github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.17.0 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.2 go.uber.org/zap v1.26.0 golang.design/x/lockfree v0.0.1 golang.org/x/crypto v0.14.0 @@ -26,7 +29,10 @@ require ( ) require ( + github.com/KyleBanks/depth v1.2.1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/bytedance/sonic v1.9.1 // indirect github.com/changkun/lockfree v0.0.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect @@ -36,6 +42,10 @@ require ( github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/spec v0.20.4 // indirect + github.com/go-openapi/swag v0.19.15 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/goccy/go-json v0.10.2 // indirect @@ -43,10 +53,12 @@ require ( github.com/golang/protobuf v1.5.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -75,6 +87,7 @@ require ( golang.org/x/tools v0.13.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/v3 v3.5.1 // indirect ) diff --git a/go.sum b/go.sum index adc186c..53fe984 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,14 @@ github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOEl github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -59,6 +65,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -87,6 +94,8 @@ github.com/function61/gokit v0.0.0-20231117065306-355fe206d542 h1:a9BTN+DOboRkVi github.com/function61/gokit v0.0.0-20231117065306-355fe206d542/go.mod h1:sJY957+7ush4oj4ElOMhUFaFIriAFNAGYzVh2tFJNy0= github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/secure v0.0.1 h1:DMMx3xXDY+MLA9kzIPHksyzC5/V5J6014c/WAmdS2gQ= github.com/gin-contrib/secure v0.0.1/go.mod h1:6kseOBFrSR3Is/kM1jDhCg/WsXAMvKJkuPvG9dGph/c= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= @@ -97,6 +106,16 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= 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.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= @@ -182,6 +201,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jonstacks/iomerge v0.0.0-20200607001240-c9a527e8abe8 h1:avdze4CXO+1TsCV84EH7ueX5WOc0GDjDYCyQWlC51Lo= github.com/jonstacks/iomerge v0.0.0-20200607001240-c9a527e8abe8/go.mod h1:D+xdhbGYvTi/6hHTULOhUiYwEM89FvmRfPKEms6MJsc= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= @@ -207,6 +228,10 @@ github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -222,6 +247,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= @@ -266,6 +293,7 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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= @@ -275,6 +303,12 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= +github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= 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 v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -285,6 +319,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -308,6 +343,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= @@ -346,6 +382,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -379,7 +416,10 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -401,6 +441,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -436,15 +477,21 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -455,6 +502,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -511,6 +559,7 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -615,15 +664,18 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= diff --git a/internal/api/rest/docs/docs.go b/internal/api/rest/docs/docs.go new file mode 100644 index 0000000..7ae25d0 --- /dev/null +++ b/internal/api/rest/docs/docs.go @@ -0,0 +1,268 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/config": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Prints app configuration in JSON format.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "App configuration.", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/config.Config" + } + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/status": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Returns forwards in JSON format. Forwards without domain may be inactive or not active yet.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Forwards \u0026 servers status.", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/server.ServerStatus" + } + } + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "definitions": { + "config.API": { + "type": "object", + "properties": { + "plugin": { + "$ref": "#/definitions/config.PluginAPI" + }, + "rest": { + "$ref": "#/definitions/config.WebAPI" + } + } + }, + "config.Config": { + "type": "object", + "properties": { + "api": { + "$ref": "#/definitions/config.API" + }, + "debug": { + "type": "boolean" + }, + "default_server": { + "type": "string" + }, + "docker": { + "$ref": "#/definitions/config.DockerConfig" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/config.Server" + } + } + } + }, + "config.DockerConfig": { + "type": "object", + "properties": { + "cert_path": { + "type": "string" + }, + "from_env": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "tls_verify": { + "type": "boolean" + }, + "version": { + "type": "string" + } + } + }, + "config.DriverParams": { + "type": "object", + "additionalProperties": true + }, + "config.DriverType": { + "type": "string", + "enum": [ + "ssh", + "plugin", + "nil" + ], + "x-enum-varnames": [ + "DriverSSH", + "DriverPlugin", + "DriverNil" + ] + }, + "config.PluginAPI": { + "type": "object", + "properties": { + "port": { + "type": "integer", + "maximum": 65535, + "minimum": 0 + } + } + }, + "config.Server": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "driver": { + "$ref": "#/definitions/config.DriverType" + }, + "name": { + "type": "string" + }, + "params": { + "$ref": "#/definitions/config.DriverParams" + } + } + }, + "config.WebAPI": { + "type": "object", + "properties": { + "port": { + "type": "integer", + "maximum": 65535, + "minimum": 0 + }, + "token": { + "type": "string" + } + } + }, + "dto.Container": { + "type": "object", + "properties": { + "domain": { + "type": "string", + "example": "https://service.localhost.run" + }, + "id": { + "type": "string", + "example": "49ec97b6a12560f98fe21a20a88c37d289c83b14cc0ada2a62b0e404512905ed" + }, + "ip": { + "type": "string", + "format": "ipv4" + }, + "names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "service-web-1" + ] + }, + "port": { + "type": "integer", + "example": 80 + }, + "remote_host": { + "type": "string", + "example": "hostname" + } + } + }, + "server.Connections": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/dto.Container" + } + }, + "server.ServerStatus": { + "type": "object", + "properties": { + "connections": { + "$ref": "#/definitions/server.Connections" + }, + "name": { + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Bearer": { + "description": "Rest API token (leave empty if it's not provided in config).", + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "", + BasePath: "/api/v1", + Schemes: []string{}, + Title: "sshpoke REST API", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/internal/api/rest/docs/swagger.json b/internal/api/rest/docs/swagger.json new file mode 100644 index 0000000..ed0ce1f --- /dev/null +++ b/internal/api/rest/docs/swagger.json @@ -0,0 +1,242 @@ +{ + "swagger": "2.0", + "info": { + "title": "sshpoke REST API", + "contact": {}, + "version": "1.0" + }, + "basePath": "/api/v1", + "paths": { + "/config": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Prints app configuration in JSON format.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "App configuration.", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/config.Config" + } + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/status": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Returns forwards in JSON format. Forwards without domain may be inactive or not active yet.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Forwards \u0026 servers status.", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/server.ServerStatus" + } + } + }, + "400": { + "description": "Bad Request" + } + } + } + } + }, + "definitions": { + "config.API": { + "type": "object", + "properties": { + "plugin": { + "$ref": "#/definitions/config.PluginAPI" + }, + "rest": { + "$ref": "#/definitions/config.WebAPI" + } + } + }, + "config.Config": { + "type": "object", + "properties": { + "api": { + "$ref": "#/definitions/config.API" + }, + "debug": { + "type": "boolean" + }, + "default_server": { + "type": "string" + }, + "docker": { + "$ref": "#/definitions/config.DockerConfig" + }, + "servers": { + "type": "array", + "items": { + "$ref": "#/definitions/config.Server" + } + } + } + }, + "config.DockerConfig": { + "type": "object", + "properties": { + "cert_path": { + "type": "string" + }, + "from_env": { + "type": "boolean" + }, + "host": { + "type": "string" + }, + "tls_verify": { + "type": "boolean" + }, + "version": { + "type": "string" + } + } + }, + "config.DriverParams": { + "type": "object", + "additionalProperties": true + }, + "config.DriverType": { + "type": "string", + "enum": [ + "ssh", + "plugin", + "nil" + ], + "x-enum-varnames": [ + "DriverSSH", + "DriverPlugin", + "DriverNil" + ] + }, + "config.PluginAPI": { + "type": "object", + "properties": { + "port": { + "type": "integer", + "maximum": 65535, + "minimum": 0 + } + } + }, + "config.Server": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "driver": { + "$ref": "#/definitions/config.DriverType" + }, + "name": { + "type": "string" + }, + "params": { + "$ref": "#/definitions/config.DriverParams" + } + } + }, + "config.WebAPI": { + "type": "object", + "properties": { + "port": { + "type": "integer", + "maximum": 65535, + "minimum": 0 + }, + "token": { + "type": "string" + } + } + }, + "dto.Container": { + "type": "object", + "properties": { + "domain": { + "type": "string", + "example": "https://service.localhost.run" + }, + "id": { + "type": "string", + "example": "49ec97b6a12560f98fe21a20a88c37d289c83b14cc0ada2a62b0e404512905ed" + }, + "ip": { + "type": "string", + "format": "ipv4" + }, + "names": { + "type": "array", + "items": { + "type": "string" + }, + "example": [ + "service-web-1" + ] + }, + "port": { + "type": "integer", + "example": 80 + }, + "remote_host": { + "type": "string", + "example": "hostname" + } + } + }, + "server.Connections": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/dto.Container" + } + }, + "server.ServerStatus": { + "type": "object", + "properties": { + "connections": { + "$ref": "#/definitions/server.Connections" + }, + "name": { + "type": "string" + } + } + } + }, + "securityDefinitions": { + "Bearer": { + "description": "Rest API token (leave empty if it's not provided in config).", + "type": "apiKey", + "name": "Authorization", + "in": "header" + } + } +} \ No newline at end of file diff --git a/internal/api/rest/docs/swagger.yaml b/internal/api/rest/docs/swagger.yaml new file mode 100644 index 0000000..16d4e5f --- /dev/null +++ b/internal/api/rest/docs/swagger.yaml @@ -0,0 +1,161 @@ +basePath: /api/v1 +definitions: + config.API: + properties: + plugin: + $ref: '#/definitions/config.PluginAPI' + rest: + $ref: '#/definitions/config.WebAPI' + type: object + config.Config: + properties: + api: + $ref: '#/definitions/config.API' + debug: + type: boolean + default_server: + type: string + docker: + $ref: '#/definitions/config.DockerConfig' + servers: + items: + $ref: '#/definitions/config.Server' + type: array + type: object + config.DockerConfig: + properties: + cert_path: + type: string + from_env: + type: boolean + host: + type: string + tls_verify: + type: boolean + version: + type: string + type: object + config.DriverParams: + additionalProperties: true + type: object + config.DriverType: + enum: + - ssh + - plugin + - nil + type: string + x-enum-varnames: + - DriverSSH + - DriverPlugin + - DriverNil + config.PluginAPI: + properties: + port: + maximum: 65535 + minimum: 0 + type: integer + type: object + config.Server: + properties: + driver: + $ref: '#/definitions/config.DriverType' + name: + type: string + params: + $ref: '#/definitions/config.DriverParams' + required: + - name + type: object + config.WebAPI: + properties: + port: + maximum: 65535 + minimum: 0 + type: integer + token: + type: string + type: object + dto.Container: + properties: + domain: + example: https://service.localhost.run + type: string + id: + example: 49ec97b6a12560f98fe21a20a88c37d289c83b14cc0ada2a62b0e404512905ed + type: string + ip: + format: ipv4 + type: string + names: + example: + - service-web-1 + items: + type: string + type: array + port: + example: 80 + type: integer + remote_host: + example: hostname + type: string + type: object + server.Connections: + additionalProperties: + $ref: '#/definitions/dto.Container' + type: object + server.ServerStatus: + properties: + connections: + $ref: '#/definitions/server.Connections' + name: + type: string + type: object +info: + contact: {} + title: sshpoke REST API + version: "1.0" +paths: + /config: + get: + consumes: + - application/json + description: Prints app configuration in JSON format. + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/config.Config' + "400": + description: Bad Request + security: + - Bearer: [] + summary: App configuration. + /status: + get: + consumes: + - application/json + description: Returns forwards in JSON format. Forwards without domain may be + inactive or not active yet. + produces: + - application/json + responses: + "200": + description: OK + schema: + additionalProperties: + $ref: '#/definitions/server.ServerStatus' + type: object + "400": + description: Bad Request + security: + - Bearer: [] + summary: Forwards & servers status. +securityDefinitions: + Bearer: + description: Rest API token (leave empty if it's not provided in config). + in: header + name: Authorization + type: apiKey +swagger: "2.0" diff --git a/internal/api/rest/handler/config.go b/internal/api/rest/handler/config.go new file mode 100644 index 0000000..432d011 --- /dev/null +++ b/internal/api/rest/handler/config.go @@ -0,0 +1,25 @@ +package handler + +import ( + "net/http" + + "github.com/Neur0toxine/sshpoke/internal/config" + "github.com/gin-gonic/gin" +) + +// @BasePath /api/v1 + +// Config returns app configuration. +// +// @Summary App configuration. +// @Schemes http +// @Description Prints app configuration in JSON format. +// @Accept json +// @Produce json +// @Success 200 {object} config.Config +// @Failure 400 +// @Router /config [get] +// @Security Bearer +func Config(c *gin.Context) { + c.JSON(http.StatusOK, config.Default) +} diff --git a/internal/api/rest/handler/docs.go b/internal/api/rest/handler/docs.go new file mode 100644 index 0000000..303c40b --- /dev/null +++ b/internal/api/rest/handler/docs.go @@ -0,0 +1,22 @@ +package handler + +import ( + "net/http" + + "github.com/Neur0toxine/sshpoke/internal/api/rest/docs" + "github.com/gin-gonic/gin" + swaggerfiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" +) + +func DocsHandler() gin.HandlerFunc { + docs.SwaggerInfo.BasePath = "/api/v1" + handler := ginSwagger.WrapHandler(swaggerfiles.Handler, ginSwagger.PersistAuthorization(true)) + return func(c *gin.Context) { + if c.Request.URL.Path == "/swagger" || c.Request.URL.Path == "/swagger/" { + c.Redirect(http.StatusMovedPermanently, "index.html") + return + } + handler(c) + } +} diff --git a/internal/api/rest/handler/status.go b/internal/api/rest/handler/status.go new file mode 100644 index 0000000..13a59a0 --- /dev/null +++ b/internal/api/rest/handler/status.go @@ -0,0 +1,23 @@ +package handler + +import ( + "net/http" + + "github.com/Neur0toxine/sshpoke/internal/server" + "github.com/gin-gonic/gin" +) + +// Status returns forwards status per server. +// +// @Summary Forwards & servers status. +// @Schemes http +// @Description Returns forwards in JSON format. Forwards without domain may be inactive or not active yet. +// @Accept json +// @Produce json +// @Success 200 {object} map[string]server.ServerStatus +// @Failure 400 +// @Router /status [get] +// @Security Bearer +func Status(c *gin.Context) { + c.JSON(http.StatusOK, server.DefaultManager.StatusMap()) +} diff --git a/internal/api/web/middleware/auth.go b/internal/api/rest/middleware/auth.go similarity index 100% rename from internal/api/web/middleware/auth.go rename to internal/api/rest/middleware/auth.go diff --git a/internal/api/web/middleware/log.go b/internal/api/rest/middleware/log.go similarity index 91% rename from internal/api/web/middleware/log.go rename to internal/api/rest/middleware/log.go index 3062e24..6b4be84 100644 --- a/internal/api/web/middleware/log.go +++ b/internal/api/rest/middleware/log.go @@ -5,7 +5,7 @@ import ( "net/http" "time" - "github.com/Neur0toxine/sshpoke/internal/api/web/middleware/log" + "github.com/Neur0toxine/sshpoke/internal/api/rest/middleware/log" "github.com/gin-gonic/gin" "go.uber.org/zap" ) diff --git a/internal/api/web/middleware/log/adapter.go b/internal/api/rest/middleware/log/adapter.go similarity index 100% rename from internal/api/web/middleware/log/adapter.go rename to internal/api/rest/middleware/log/adapter.go diff --git a/internal/api/web/server.go b/internal/api/rest/server.go similarity index 62% rename from internal/api/web/server.go rename to internal/api/rest/server.go index dfa8c8a..d8dbb6b 100644 --- a/internal/api/web/server.go +++ b/internal/api/rest/server.go @@ -1,11 +1,12 @@ -package web +//go:generate swag init --parseInternal --parseDependency --parseDepth 1 --output docs -g internal/api/rest/server.go --dir ../../../ +package rest import ( "net" "strconv" - "github.com/Neur0toxine/sshpoke/internal/api/web/handler" - "github.com/Neur0toxine/sshpoke/internal/api/web/middleware" + "github.com/Neur0toxine/sshpoke/internal/api/rest/handler" + "github.com/Neur0toxine/sshpoke/internal/api/rest/middleware" "github.com/Neur0toxine/sshpoke/internal/logger" "github.com/gin-contrib/secure" "github.com/gin-gonic/gin" @@ -18,6 +19,14 @@ const ( httpProto = "http://" ) +// @title sshpoke REST API +// @version 1.0 +// @BasePath /api/v1 +// @securityDefinitions.apikey Bearer +// @in header +// @name Authorization +// @description Rest API token (leave empty if it's not provided in config). + func StartServer(token string, port int, log *zap.SugaredLogger, debug bool) { if !debug { gin.SetMode(gin.ReleaseMode) @@ -38,10 +47,12 @@ func StartServer(token string, port int, log *zap.SugaredLogger, debug bool) { router(g, token) err := g.Run(net.JoinHostPort("127.0.0.1", strconv.Itoa(port))) if err != nil { - logger.Sugar.Errorf("cannot start Web API server on port %d: %s", port, err) + logger.Sugar.Errorf("cannot start Rest API server on port %d: %s", port, err) } } + func router(g *gin.Engine, token string) { + g.GET("/swagger/*any", handler.DocsHandler()) api := g.Group("/api/v1") { api.Use(middleware.Auth(token)) @@ -53,5 +64,6 @@ func router(g *gin.Engine, token string) { func secureConfig() secure.Config { cfg := secure.DefaultConfig() cfg.SSLRedirect = false + cfg.ContentSecurityPolicy = cfg.ContentSecurityPolicy + " 'unsafe-inline'; img-src 'self' data:" return cfg } diff --git a/internal/api/web/handler/config.go b/internal/api/web/handler/config.go deleted file mode 100644 index 5d4c875..0000000 --- a/internal/api/web/handler/config.go +++ /dev/null @@ -1,12 +0,0 @@ -package handler - -import ( - "net/http" - - "github.com/Neur0toxine/sshpoke/internal/config" - "github.com/gin-gonic/gin" -) - -func Config(c *gin.Context) { - c.JSON(http.StatusOK, config.Default) -} diff --git a/internal/api/web/handler/status.go b/internal/api/web/handler/status.go deleted file mode 100644 index 61dcb75..0000000 --- a/internal/api/web/handler/status.go +++ /dev/null @@ -1,12 +0,0 @@ -package handler - -import ( - "net/http" - - "github.com/Neur0toxine/sshpoke/internal/server" - "github.com/gin-gonic/gin" -) - -func Status(c *gin.Context) { - c.JSON(http.StatusOK, server.DefaultManager.StatusMap()) -} diff --git a/internal/config/model.go b/internal/config/model.go index a1acc6c..67fe599 100644 --- a/internal/config/model.go +++ b/internal/config/model.go @@ -19,7 +19,7 @@ type Config struct { } type API struct { - Web WebAPI `mapstructure:"web" json:"web"` + Rest WebAPI `mapstructure:"rest" json:"rest"` Plugin PluginAPI `mapstructure:"plugin" json:"plugin"` } diff --git a/pkg/dto/models.go b/pkg/dto/models.go index 156084f..3f9b151 100644 --- a/pkg/dto/models.go +++ b/pkg/dto/models.go @@ -52,11 +52,11 @@ type EventStatus struct { } type Container struct { - ID string `json:"id"` - Names []string `json:"names"` - IP net.IP `json:"ip"` - Port uint16 `json:"port"` + ID string `json:"id" example:"49ec97b6a12560f98fe21a20a88c37d289c83b14cc0ada2a62b0e404512905ed"` + Names []string `json:"names" example:"service-web-1"` + IP net.IP `json:"ip" swaggertype:"string" format:"ipv4"` + Port uint16 `json:"port" example:"80"` Server string `json:"-"` - RemoteHost string `json:"remote_host,omitempty"` - Domain string `json:"domain"` + RemoteHost string `json:"remote_host,omitempty" example:"hostname"` + Domain string `json:"domain" example:"https://service.localhost.run"` }