From 256c566dfe838603fbe632c2cc5818730338f753 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 30 Sep 2017 17:25:04 -0500 Subject: [PATCH 1/6] Change to using yml for configuration files --- .gitignore | 3 ++- api/_testdata/config.json | 5 ----- api/_testdata/config.yml | 1 + api/auth_test.go | 2 +- api/routes_server.go | 2 +- command/root.go | 2 +- config.example.json | 4 +--- config.yml | 28 ++++++++++++++++++++++++++++ config.yml.example | 28 ++++++++++++++++++++++++++++ config/config.go | 3 ++- config/config_test.go | 2 +- config/keys.go | 6 +++--- tools/logging.go | 2 +- 13 files changed, 70 insertions(+), 18 deletions(-) delete mode 100644 api/_testdata/config.json create mode 100644 api/_testdata/config.yml create mode 100644 config.yml create mode 100644 config.yml.example diff --git a/.gitignore b/.gitignore index 958ec78..5b8833a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.dll *.so *.dylib +.idea/* # Test binary, build with `go test -c` *.test @@ -20,7 +21,7 @@ /logs/* # ignore configuration file -/config.json +/config.yml # Ignore Vagrant stuff /.vagrant diff --git a/api/_testdata/config.json b/api/_testdata/config.json deleted file mode 100644 index 327c993..0000000 --- a/api/_testdata/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "authKeys": [ - "existingkey" - ] -} diff --git a/api/_testdata/config.yml b/api/_testdata/config.yml new file mode 100644 index 0000000..2d04127 --- /dev/null +++ b/api/_testdata/config.yml @@ -0,0 +1 @@ +authKey: 'existingkey' diff --git a/api/auth_test.go b/api/auth_test.go index 086f4a0..c66e868 100644 --- a/api/auth_test.go +++ b/api/auth_test.go @@ -12,7 +12,7 @@ import ( "github.com/Pterodactyl/wings/control" ) -const configFile = "_testdata/config.json" +const configFile = "_testdata/config.yml" func TestAuthHandler(t *testing.T) { gin.SetMode(gin.ReleaseMode) diff --git a/api/routes_server.go b/api/routes_server.go index 955527a..9fa4e8c 100644 --- a/api/routes_server.go +++ b/api/routes_server.go @@ -7,7 +7,7 @@ func (api *API) registerServerRoutes() { api.router.POST("/servers", AuthHandler("c:create"), handlePostServers) api.router.GET("/servers/:server", AuthHandler("s:get"), handleGetServer) api.router.PATCH("/servers/:server", AuthHandler("s:config"), handlePatchServer) - api.router.DELETE("/servers/:server", AuthHandler("g:server:delete"), handleDeleteServer) + //api.router.DELETE("/servers/:server", AuthHandler("g:server:delete"), handleDeleteServer) api.router.POST("/servers/:server/reinstall", AuthHandler("s:install-server"), handlePostServerReinstall) api.router.POST("/servers/:server/rebuild", AuthHandler("g:server:rebuild"), handlePostServerRebuild) diff --git a/command/root.go b/command/root.go index ba4d945..148bfc3 100644 --- a/command/root.go +++ b/command/root.go @@ -20,7 +20,7 @@ var RootCommand = &cobra.Command{ var configPath string func init() { - RootCommand.Flags().StringVarP(&configPath, "config", "c", "./config.json", "Allows to set the path of the configuration file.") + RootCommand.Flags().StringVarP(&configPath, "config", "c", "./config.yml", "Allows to set the path of the configuration file.") } // Execute registers the RootCommand diff --git a/config.example.json b/config.example.json index 2ec2f77..195d48f 100644 --- a/config.example.json +++ b/config.example.json @@ -34,7 +34,5 @@ "level": "info", "deleteAfterDays": 100 }, - "authKeys": [ - "somekey" - ] + "authKey": "somekey" } diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..4c4d1a0 --- /dev/null +++ b/config.yml @@ -0,0 +1,28 @@ +debug: true +data: '/srv/daemon-data' +api: + host: '0.0.0.0' + port: 8080 + ssl: + enabled: false + cert: '' + key: '' + uploads: + maximumSize: 150000000 +docker: + socket: '/var/run/docker.sock' + autoupdateImages: true + networkInterface: '172.18.0.1' + timezonePath: '/etc/timezone' +sftp: + host: '0.0.0.0' + port: 2022 +query: + killOnFail: false + failLimit: 5 +remote: 'http://pterodactyl.app' +log: + path: './logs/' + level: 'debug' + deleteAfterDays: 10 +authKey: 'test123' diff --git a/config.yml.example b/config.yml.example new file mode 100644 index 0000000..a170504 --- /dev/null +++ b/config.yml.example @@ -0,0 +1,28 @@ +debug: false +data: '/srv/daemon-data' +api: + host: '0.0.0.0' + port: 8080 + ssl: + enabled: false + cert: '' + key: '' + uploads: + maximumSize: 150000000 +docker: + socket: '/var/run/docker.sock' + autoupdateImages: true + networkInterface: '172.18.0.1' + timezonePath: '/etc/timezone' +sftp: + host: '0.0.0.0' + port: 2022 +query: + killOnFail: true + failLimit: 5 +remote: 'http://example.com' +log: + path: './logs/' + level: 'info' + deleteAfterDays: 10 +authKey: 'test123' diff --git a/config/config.go b/config/config.go index 47bef4a..7635697 100644 --- a/config/config.go +++ b/config/config.go @@ -10,6 +10,7 @@ func LoadConfiguration(path string) error { viper.SetConfigFile(path) } else { viper.AddConfigPath("./") + viper.SetConfigType("yaml") viper.SetConfigName("config") } @@ -49,7 +50,7 @@ func setDefaults() { // ContainsAuthKey checks wether the config contains a specified authentication key func ContainsAuthKey(key string) bool { - for _, k := range viper.GetStringSlice(AuthKeys) { + for _, k := range viper.GetStringSlice(AuthKey) { if k == key { return true } diff --git a/config/config_test.go b/config/config_test.go index 3a89d1f..1773208 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -8,7 +8,7 @@ import ( "github.com/stretchr/testify/assert" ) -const configFile = "../config.example.json" +const configFile = "../config.yml.example" func TestLoadConfiguraiton(t *testing.T) { err := LoadConfiguration(configFile) diff --git a/config/keys.go b/config/keys.go index 5764edb..fcf6304 100644 --- a/config/keys.go +++ b/config/keys.go @@ -21,7 +21,7 @@ const ( SSLGenerateLetsencrypt = "api.ssl.letsencrypt" // SSLCertificate is a string containing the location of // a ssl certificate to use - SSLCertificate = "api.ssl.certificate" + SSLCertificate = "api.ssl.cert" // SSLKey is a string containing the location of the key // for the ssl certificate SSLKey = "api.ssl.key" @@ -61,6 +61,6 @@ const ( // logs should be stored. They will be deleted after. If set to 0 // logs will be stored indefinitely. LogDeleteAfterDays = "log.deleteAfterDays" - // AuthKeys contains an array of auth keys that will be replaced by something better - AuthKeys = "authkeys" + // AuthKey contains a key that will be replaced by something better + AuthKey = "authKey" ) diff --git a/tools/logging.go b/tools/logging.go index 24ea9b1..f7183ef 100644 --- a/tools/logging.go +++ b/tools/logging.go @@ -3,7 +3,7 @@ package tools import ( "time" - rotatelogs "github.com/lestrrat/go-file-rotatelogs" + "github.com/lestrrat/go-file-rotatelogs" "github.com/rifflock/lfshook" log "github.com/sirupsen/logrus" "github.com/spf13/viper" From 1bfc016e1b964831fdc1300d03fb4fc2b122627b Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 30 Sep 2017 18:35:44 -0500 Subject: [PATCH 2/6] Clean up route handling --- api/api.go | 30 ++++++---------- api/{handlers.go => core_routes.go} | 5 ++- api/file_routes.go | 47 ++++++++++++++++++++++++ api/handlers_server.go | 55 ----------------------------- api/handlers_server_files.go | 51 -------------------------- api/routes.go | 53 ++++++++++++++++++++++++--- api/routes_server.go | 20 ----------- api/routes_server_files.go | 20 ----------- api/server_routes.go | 55 +++++++++++++++++++++++++++++ 9 files changed, 163 insertions(+), 173 deletions(-) rename api/{handlers.go => core_routes.go} (92%) create mode 100644 api/file_routes.go delete mode 100644 api/handlers_server.go delete mode 100644 api/handlers_server_files.go delete mode 100644 api/routes_server.go delete mode 100644 api/routes_server_files.go create mode 100644 api/server_routes.go diff --git a/api/api.go b/api/api.go index 61cdb95..9f3a0bb 100644 --- a/api/api.go +++ b/api/api.go @@ -11,34 +11,26 @@ import ( "github.com/Pterodactyl/wings/config" ) -// API is a grouping struct for the api -type API struct { +type InternalAPI struct { router *gin.Engine } -// NewAPI creates a new Api object -func NewAPI() API { - return API{} +func NewAPI() InternalAPI { + return InternalAPI{} } -// Listen starts the api http server -func (api *API) Listen() { +// Configure the API and begin listening on the configured IP and Port. +func (api *InternalAPI) Listen() { + listener := fmt.Sprintf("%s:%d", viper.GetString(config.APIHost), viper.GetInt(config.APIPort)) + if !viper.GetBool(config.Debug) { gin.SetMode(gin.ReleaseMode) } api.router = gin.Default() + api.RegisterRoutes() - api.registerRoutes() - - listenString := fmt.Sprintf("%s:%d", viper.GetString(config.APIHost), viper.GetInt(config.APIPort)) - - api.router.Run(listenString) - - log.Info("Now listening on %s", listenString) - log.Fatal(http.ListenAndServe(listenString, nil)) -} - -func getRoot(c *gin.Context) { - c.String(http.StatusOK, "hello!") + api.router.Run(listener) + log.Info("Now listening on %s", listener) + log.Fatal(http.ListenAndServe(listener, nil)) } diff --git a/api/handlers.go b/api/core_routes.go similarity index 92% rename from api/handlers.go rename to api/core_routes.go index 73b4c95..dff0279 100644 --- a/api/handlers.go +++ b/api/core_routes.go @@ -11,8 +11,7 @@ import ( log "github.com/sirupsen/logrus" ) -// handleGetIndex handles GET / -func handleGetIndex(c *gin.Context) { +func GetIndex(c *gin.Context) { auth := GetContextAuthManager(c) if auth != nil && auth.HasPermission("c:info") { @@ -58,6 +57,6 @@ func handleGetIndex(c *gin.Context) { } // handlePatchConfig handles PATCH /config -func handlePatchConfig(c *gin.Context) { +func PatchConfiguration(c *gin.Context) { } diff --git a/api/file_routes.go b/api/file_routes.go new file mode 100644 index 0000000..a5943e9 --- /dev/null +++ b/api/file_routes.go @@ -0,0 +1,47 @@ +package api + +import "github.com/gin-gonic/gin" + +func StoreDirectory(c *gin.Context) { + +} + +func ListDirectory(c *gin.Context) { + +} + +func CopyFile(c *gin.Context) { + +} + +func MoveFile(c *gin.Context) { + +} + +func CompressFile(c *gin.Context) { + +} + +func DecompressFile(c *gin.Context) { + +} + +func StatFile(c *gin.Context) { + +} + +func ReadFileContents(c *gin.Context) { + +} + +func WriteFileContents(c *gin.Context) { + +} + +func DeleteFile(c *gin.Context) { + +} + +func DownloadFile(c *gin.Context) { + +} diff --git a/api/handlers_server.go b/api/handlers_server.go deleted file mode 100644 index 5d4430e..0000000 --- a/api/handlers_server.go +++ /dev/null @@ -1,55 +0,0 @@ -package api - -import "github.com/gin-gonic/gin" - -func handleGetServers(c *gin.Context) { - -} - -func handlePostServers(c *gin.Context) { - -} - -func handleDeleteServers(c *gin.Context) { - -} - -func handleGetServer(c *gin.Context) { - -} - -func handlePatchServer(c *gin.Context) { - -} - -func handlePostServerReinstall(c *gin.Context) { - -} - -func handlePostServerPassword(c *gin.Context) { - -} - -func handlePostServerRebuild(c *gin.Context) { - -} - -func handlePutServerPower(c *gin.Context) { - -} - -func handlePostServerCommand(c *gin.Context) { - -} - -func handleGetServerLog(c *gin.Context) { - -} - -func handlePostServerSuspend(c *gin.Context) { - -} - -func handlePostServerUnsuspend(c *gin.Context) { - -} diff --git a/api/handlers_server_files.go b/api/handlers_server_files.go deleted file mode 100644 index d4c5ae3..0000000 --- a/api/handlers_server_files.go +++ /dev/null @@ -1,51 +0,0 @@ -package api - -import "github.com/gin-gonic/gin" - -func handlePostFilesFolder(c *gin.Context) { - -} - -func handleGetDirectory(c *gin.Context) { - -} - -func handlePostFileCopy(c *gin.Context) { - -} - -func handlePostFileMove(c *gin.Context) { - -} - -func handlePostFileDelete(c *gin.Context) { - -} - -func handlePostFileCompress(c *gin.Context) { - -} - -func handlePostFileDecompress(c *gin.Context) { - -} - -func handleGetFileStat(c *gin.Context) { - -} - -func handleGetFile(c *gin.Context) { - -} - -func handlePostFile(c *gin.Context) { - -} - -func handleDeleteFile(c *gin.Context) { - -} - -func handleGetDownloadFile(c *gin.Context) { - -} diff --git a/api/routes.go b/api/routes.go index a6451c4..cc2063c 100644 --- a/api/routes.go +++ b/api/routes.go @@ -1,9 +1,52 @@ package api -func (api *API) registerRoutes() { - api.router.GET("/", AuthHandler(""), handleGetIndex) - api.router.PATCH("/config", AuthHandler("c:config"), handlePatchConfig) +func (api *InternalAPI) RegisterRoutes() { + api.router.GET("/", AuthHandler(""), GetIndex) + api.router.PATCH("/config", AuthHandler("c:config"), PatchConfiguration) - api.registerServerRoutes() - api.registerServerFileRoutes() + // Register routes for v1 of the API. This API should be fully backwards compatable with + // the existing Nodejs Daemon API. + v1 := api.router.Group("/v1") + { + v1BaseRoutes := v1.Group("/server") + { + v1BaseRoutes.GET("/", AuthHandler("c:list"), ListServers) + v1BaseRoutes.POST("/", AuthHandler("c:create"), StoreServer) + } + + v1ServerRoutes := v1.Group("/server/:server") + { + v1ServerRoutes.GET("/", AuthHandler("s:get"), ViewServer) + v1ServerRoutes.GET("/log", AuthHandler("s:console"), GetLogForServer) + + v1ServerRoutes.POST("/reinstall", AuthHandler("s:install-server"), ReinstallServer) + v1ServerRoutes.POST("/rebuild", AuthHandler("g:server:rebuild"), RebuildServer) + v1ServerRoutes.POST("/password", AuthHandler(""), SetServerPassword) + v1ServerRoutes.POST("/power", AuthHandler("s:power"), PowerServer) + v1ServerRoutes.POST("/command", AuthHandler("s:command"), SendCommandToServer) + v1ServerRoutes.POST("/suspend", AuthHandler(""), SuspendServer) + v1ServerRoutes.POST("/unsuspend", AuthHandler(""), UnsuspendServer) + + v1ServerRoutes.PATCH("/", AuthHandler("s:config"), UpdateServer) + v1ServerRoutes.DELETE("/", AuthHandler("g:server:delete"), DeleteServer) + } + + v1ServerFileRoutes := v1.Group("/server/:server/files") + { + v1ServerFileRoutes.GET("/file/:file", AuthHandler("s:files:read"), ReadFileContents) + v1ServerFileRoutes.GET("/stat/:file", AuthHandler("s:files:get"), StatFile) + v1ServerFileRoutes.GET("/dir/:directory", AuthHandler("s:files:get"), ListDirectory) + v1ServerFileRoutes.GET("/download/:token", DownloadFile) + + v1ServerFileRoutes.POST("/dir/:directory", AuthHandler("s:files:create"), StoreDirectory) + v1ServerFileRoutes.POST("/file/:file", AuthHandler("s:files:post"), WriteFileContents) + v1ServerFileRoutes.POST("/copy/:file", AuthHandler("s:files:copy"), CopyFile) + v1ServerFileRoutes.POST("/move/:file", AuthHandler("s:files:move"), MoveFile) + v1ServerFileRoutes.POST("/rename/:file", AuthHandler("s:files:move"), MoveFile) + v1ServerFileRoutes.POST("/compress/:file", AuthHandler("s:files:compress"), CompressFile) + v1ServerFileRoutes.POST("/decompress/:file", AuthHandler("s:files:decompress"), DecompressFile) + + v1ServerFileRoutes.DELETE("/file/:file", AuthHandler("s:files:delete"), DeleteFile) + } + } } diff --git a/api/routes_server.go b/api/routes_server.go deleted file mode 100644 index 9fa4e8c..0000000 --- a/api/routes_server.go +++ /dev/null @@ -1,20 +0,0 @@ -package api - -func (api *API) registerServerRoutes() { - - api.router.GET("/servers", AuthHandler("c:list"), handleGetServers) - - api.router.POST("/servers", AuthHandler("c:create"), handlePostServers) - api.router.GET("/servers/:server", AuthHandler("s:get"), handleGetServer) - api.router.PATCH("/servers/:server", AuthHandler("s:config"), handlePatchServer) - //api.router.DELETE("/servers/:server", AuthHandler("g:server:delete"), handleDeleteServer) - - api.router.POST("/servers/:server/reinstall", AuthHandler("s:install-server"), handlePostServerReinstall) - api.router.POST("/servers/:server/rebuild", AuthHandler("g:server:rebuild"), handlePostServerRebuild) - api.router.POST("/servers/:server/password", AuthHandler(""), handlePostServerPassword) - api.router.POST("/servers/:server/power", AuthHandler("s:power"), handlePutServerPower) - api.router.POST("/servers/:server/command", AuthHandler("s:command"), handlePostServerCommand) - api.router.GET("/servers/:server/log", AuthHandler("s:console"), handleGetServerLog) - api.router.POST("/servers/:server/suspend", AuthHandler(""), handlePostServerSuspend) - api.router.POST("/servers/:server/unsuspend", AuthHandler(""), handlePostServerUnsuspend) -} diff --git a/api/routes_server_files.go b/api/routes_server_files.go deleted file mode 100644 index 747e05c..0000000 --- a/api/routes_server_files.go +++ /dev/null @@ -1,20 +0,0 @@ -package api - -func (api *API) registerServerFileRoutes() { - api.router.GET("/servers/:server/files/file/:file", AuthHandler("s:files:read"), handleGetFile) - api.router.GET("/servers/:server/files/stat/:file", AuthHandler("s:files:"), handleGetFileStat) - api.router.GET("/servers/:server/files/dir/:directory", AuthHandler("s:files:get"), handleGetDirectory) - - api.router.POST("/servers/:server/files/dir/:directory", AuthHandler("s:files:create"), handlePostFilesFolder) - api.router.POST("/servers/:server/files/file/:file", AuthHandler("s:files:post"), handlePostFile) - - api.router.POST("/servers/:server/files/copy/:file", AuthHandler("s:files:copy"), handlePostFileCopy) - api.router.POST("/servers/:server/files/move/:file", AuthHandler("s:files:move"), handlePostFileMove) - api.router.POST("/servers/:server/files/rename/:file", AuthHandler("s:files:move"), handlePostFileMove) - api.router.POST("/servers/:server/files/compress/:file", AuthHandler("s:files:compress"), handlePostFileCompress) - api.router.POST("/servers/:server/files/decompress/:file", AuthHandler("s:files:decompress"), handlePostFileDecompress) - - api.router.DELETE("/servers/:server/files/file/:file", AuthHandler("s:files:delete"), handleDeleteFile) - - api.router.GET("/servers/:server/files/download/:token", handleGetDownloadFile) -} diff --git a/api/server_routes.go b/api/server_routes.go new file mode 100644 index 0000000..775b956 --- /dev/null +++ b/api/server_routes.go @@ -0,0 +1,55 @@ +package api + +import "github.com/gin-gonic/gin" + +func ListServers(c *gin.Context) { + +} + +func StoreServer(c *gin.Context) { + +} + +func DeleteServer(c *gin.Context) { + +} + +func ViewServer(c *gin.Context) { + +} + +func UpdateServer(c *gin.Context) { + +} + +func ReinstallServer(c *gin.Context) { + +} + +func SetServerPassword(c *gin.Context) { + +} + +func RebuildServer(c *gin.Context) { + +} + +func PowerServer(c *gin.Context) { + +} + +func SendCommandToServer(c *gin.Context) { + +} + +func GetLogForServer(c *gin.Context) { + +} + +func SuspendServer(c *gin.Context) { + +} + +func UnsuspendServer(c *gin.Context) { + +} From 339d2d286d21eef066de7ee64f8e39ada0fa6607 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 30 Sep 2017 18:37:08 -0500 Subject: [PATCH 3/6] Forgotten routes into v1 namespace --- api/routes.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/routes.go b/api/routes.go index cc2063c..d4b3cec 100644 --- a/api/routes.go +++ b/api/routes.go @@ -1,13 +1,13 @@ package api func (api *InternalAPI) RegisterRoutes() { - api.router.GET("/", AuthHandler(""), GetIndex) - api.router.PATCH("/config", AuthHandler("c:config"), PatchConfiguration) - // Register routes for v1 of the API. This API should be fully backwards compatable with // the existing Nodejs Daemon API. v1 := api.router.Group("/v1") { + v1.GET("/", AuthHandler(""), GetIndex) + v1.PATCH("/config", AuthHandler("c:config"), PatchConfiguration) + v1BaseRoutes := v1.Group("/server") { v1BaseRoutes.GET("/", AuthHandler("c:list"), ListServers) From 39a79add7c4463d814dcbf7925807a66cfac41b6 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 30 Sep 2017 18:42:33 -0500 Subject: [PATCH 4/6] Untrack --- config.example.json | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 config.example.json diff --git a/config.example.json b/config.example.json deleted file mode 100644 index 195d48f..0000000 --- a/config.example.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "debug": false, - "dataPath": "/srv/daemon-data", - "api": { - "host": "0.0.0.0", - "port": 8080, - "ssl": { - "enabled": false, - "generateLetsEncrypt": true, - "certificate": "/etc/letsencrypt/live/pterodactyl.app/fullchain.pem", - "key": "/etc/letsencrypt/live/pterodactyl.app/privkey.pem" - }, - "uploads": { - "maximumSize": 150000000 - } - }, - "docker": { - "socket": "/var/run/docker.sock", - "autoupdateImages": true, - "networkInterface": "172.18.0.1", - "timezonePath": "/etc/timezone" - }, - "sftp": { - "host": "0.0.0.0", - "port": 2022 - }, - "query": { - "killOnFail": false, - "failLimit": 5 - }, - "remote": "https://pterodactyl.app", - "log": { - "path": "logs/", - "level": "info", - "deleteAfterDays": 100 - }, - "authKey": "somekey" -} From edc189001fde23949309f306f2e038717f225a09 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 30 Sep 2017 18:43:01 -0500 Subject: [PATCH 5/6] Remove ignored files --- config.yml | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 config.yml diff --git a/config.yml b/config.yml deleted file mode 100644 index 4c4d1a0..0000000 --- a/config.yml +++ /dev/null @@ -1,28 +0,0 @@ -debug: true -data: '/srv/daemon-data' -api: - host: '0.0.0.0' - port: 8080 - ssl: - enabled: false - cert: '' - key: '' - uploads: - maximumSize: 150000000 -docker: - socket: '/var/run/docker.sock' - autoupdateImages: true - networkInterface: '172.18.0.1' - timezonePath: '/etc/timezone' -sftp: - host: '0.0.0.0' - port: 2022 -query: - killOnFail: false - failLimit: 5 -remote: 'http://pterodactyl.app' -log: - path: './logs/' - level: 'debug' - deleteAfterDays: 10 -authKey: 'test123' From 90fd485edfd70326b65fadd4663f658972723374 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 30 Sep 2017 19:25:45 -0500 Subject: [PATCH 6/6] Lets not, please. --- api/api.go | 1 + 1 file changed, 1 insertion(+) diff --git a/api/api.go b/api/api.go index 9f3a0bb..1ed5dc7 100644 --- a/api/api.go +++ b/api/api.go @@ -28,6 +28,7 @@ func (api *InternalAPI) Listen() { } api.router = gin.Default() + api.router.RedirectTrailingSlash = false api.RegisterRoutes() api.router.Run(listener)