diff --git a/Makefile b/Makefile index 361980d1..b8a78bb8 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ GIT_TAG := $(shell git describe --tags --always) GIT_COMMIT := $(shell git rev-parse HEAD) GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD) -LDFLAGS := -X $(PACKAGE)/internal/global.GitTag=$(GIT_TAG) -X $(PACKAGE)/internal/global.GitCommitID=$(GIT_COMMIT) -X $(PACKAGE)/internal/global.GitBranch=$(GIT_BRANCH) +LDFLAGS := -X $(PACKAGE)/internal/utils.GitTag=$(GIT_TAG) -X $(PACKAGE)/internal/utils.GitCommitID=$(GIT_COMMIT) -X $(PACKAGE)/internal/utils.GitBranch=$(GIT_BRANCH) .PHONY: all build run clean swag @@ -27,7 +27,7 @@ swag: build: swag @echo Building $(PACKAGE)... - @go build -ldflags "-linkmode external -w -s $(LDFLAGS)" -o ./build/$(BINARY) + @go build -ldflags "-linkmode external -w -s $(LDFLAGS)" -o ./build/$(BINARY) $(PACKAGE)/cmd/cloudsdale @echo Build finished. run: swag diff --git a/api/docs.go b/api/docs.go index ee002a88..854d6b84 100644 --- a/api/docs.go +++ b/api/docs.go @@ -445,64 +445,6 @@ const docTemplate = `{ "responses": {} } }, - "/challenges/{id}/hints": { - "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Challenge" - ], - "summary": "创建提示", - "responses": {} - } - }, - "/challenges/{id}/hints/{hint_id}": { - "put": { - "security": [ - { - "ApiKeyAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Challenge" - ], - "summary": "更新提示", - "responses": {} - }, - "delete": { - "security": [ - { - "ApiKeyAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Challenge" - ], - "summary": "删除提示", - "responses": {} - } - }, "/configs/": { "get": { "description": "配置全部查询", @@ -2125,12 +2067,6 @@ const docTemplate = `{ "$ref": "#/definitions/model.Flag" } }, - "hints": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Hint" - } - }, "id": { "description": "The challenge's id. As primary key.", "type": "integer" @@ -2365,43 +2301,6 @@ const docTemplate = `{ } } }, - "model.Hint": { - "type": "object", - "properties": { - "challenge": { - "description": "The challenge which the hint belongs to.", - "allOf": [ - { - "$ref": "#/definitions/model.Challenge" - } - ] - }, - "challenge_id": { - "description": "The challenge which the hint belongs to.", - "type": "integer" - }, - "content": { - "description": "The content of the hint.", - "type": "string" - }, - "created_at": { - "description": "The hint's creation time.", - "type": "integer" - }, - "id": { - "description": "The hint's id.", - "type": "integer" - }, - "published_at": { - "description": "When the hint will be published.", - "type": "integer" - }, - "updated_at": { - "description": "The hint's last update time.", - "type": "integer" - } - } - }, "model.Port": { "type": "object", "properties": { @@ -2627,10 +2526,6 @@ const docTemplate = `{ "description": "The user's password. Crypt.", "type": "string" }, - "signature": { - "description": "The user's signature.", - "type": "string" - }, "teams": { "description": "The user's teams.", "type": "array", diff --git a/api/swagger.json b/api/swagger.json index 11a1b9c8..07eff04a 100644 --- a/api/swagger.json +++ b/api/swagger.json @@ -436,64 +436,6 @@ "responses": {} } }, - "/challenges/{id}/hints": { - "post": { - "security": [ - { - "ApiKeyAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Challenge" - ], - "summary": "创建提示", - "responses": {} - } - }, - "/challenges/{id}/hints/{hint_id}": { - "put": { - "security": [ - { - "ApiKeyAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Challenge" - ], - "summary": "更新提示", - "responses": {} - }, - "delete": { - "security": [ - { - "ApiKeyAuth": [] - } - ], - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "tags": [ - "Challenge" - ], - "summary": "删除提示", - "responses": {} - } - }, "/configs/": { "get": { "description": "配置全部查询", @@ -2116,12 +2058,6 @@ "$ref": "#/definitions/model.Flag" } }, - "hints": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Hint" - } - }, "id": { "description": "The challenge's id. As primary key.", "type": "integer" @@ -2356,43 +2292,6 @@ } } }, - "model.Hint": { - "type": "object", - "properties": { - "challenge": { - "description": "The challenge which the hint belongs to.", - "allOf": [ - { - "$ref": "#/definitions/model.Challenge" - } - ] - }, - "challenge_id": { - "description": "The challenge which the hint belongs to.", - "type": "integer" - }, - "content": { - "description": "The content of the hint.", - "type": "string" - }, - "created_at": { - "description": "The hint's creation time.", - "type": "integer" - }, - "id": { - "description": "The hint's id.", - "type": "integer" - }, - "published_at": { - "description": "When the hint will be published.", - "type": "integer" - }, - "updated_at": { - "description": "The hint's last update time.", - "type": "integer" - } - } - }, "model.Port": { "type": "object", "properties": { @@ -2618,10 +2517,6 @@ "description": "The user's password. Crypt.", "type": "string" }, - "signature": { - "description": "The user's signature.", - "type": "string" - }, "teams": { "description": "The user's teams.", "type": "array", diff --git a/api/swagger.yaml b/api/swagger.yaml index f5791f9a..5aac9d5b 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -62,10 +62,6 @@ definitions: items: $ref: '#/definitions/model.Flag' type: array - hints: - items: - $ref: '#/definitions/model.Hint' - type: array id: description: The challenge's id. As primary key. type: integer @@ -234,31 +230,6 @@ definitions: pts: type: integer type: object - model.Hint: - properties: - challenge: - allOf: - - $ref: '#/definitions/model.Challenge' - description: The challenge which the hint belongs to. - challenge_id: - description: The challenge which the hint belongs to. - type: integer - content: - description: The content of the hint. - type: string - created_at: - description: The hint's creation time. - type: integer - id: - description: The hint's id. - type: integer - published_at: - description: When the hint will be published. - type: integer - updated_at: - description: The hint's last update time. - type: integer - type: object model.Port: properties: challenge: @@ -410,9 +381,6 @@ definitions: password: description: The user's password. Crypt. type: string - signature: - description: The user's signature. - type: string teams: description: The user's teams. items: @@ -1084,41 +1052,6 @@ paths: summary: 更新 flag tags: - Challenge - /challenges/{id}/hints: - post: - consumes: - - application/json - produces: - - application/json - responses: {} - security: - - ApiKeyAuth: [] - summary: 创建提示 - tags: - - Challenge - /challenges/{id}/hints/{hint_id}: - delete: - consumes: - - application/json - produces: - - application/json - responses: {} - security: - - ApiKeyAuth: [] - summary: 删除提示 - tags: - - Challenge - put: - consumes: - - application/json - produces: - - application/json - responses: {} - security: - - ApiKeyAuth: [] - summary: 更新提示 - tags: - - Challenge /configs/: get: consumes: diff --git a/go.mod b/go.mod index ef077555..fc22d8e0 100644 --- a/go.mod +++ b/go.mod @@ -41,10 +41,12 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/bytedance/sonic v1.11.3 // indirect github.com/casbin/govaluate v1.1.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect github.com/containerd/log v0.1.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/distribution/reference v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -94,8 +96,10 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pelletier/go-toml/v2 v2.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/redis/go-redis/v9 v9.5.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect diff --git a/go.sum b/go.sum index 3cae410b..f5b400a7 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,8 @@ github.com/casbin/govaluate v1.1.1 h1:J1rFKIBhiC5xr0APd5HP6rDL+xt+BRoyq1pa4o2i/5 github.com/casbin/govaluate v1.1.1/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= @@ -38,6 +40,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= @@ -206,6 +210,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= @@ -217,6 +223,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/redis/go-redis/v9 v9.5.1 h1:H1X4D3yHPaYrkL5X06Wh6xNVM/pX0Ft4RV0vMGvLBh8= +github.com/redis/go-redis/v9 v9.5.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578 h1:VstopitMQi3hZP0fzvnsLmzXZdQGc4bEcgu24cp+d4M= github.com/remyoudompheng/bigfft v0.0.0-20230126093431-47fa9a501578/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= diff --git a/internal/app/app.go b/internal/app/app.go index 9922114f..2cccd4c6 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -3,19 +3,20 @@ package app import ( "fmt" _ "github.com/elabosak233/cloudsdale/api" - "github.com/elabosak233/cloudsdale/internal/app/assets" "github.com/elabosak233/cloudsdale/internal/app/config" "github.com/elabosak233/cloudsdale/internal/app/db" "github.com/elabosak233/cloudsdale/internal/app/logger" "github.com/elabosak233/cloudsdale/internal/app/logger/adapter" + "github.com/elabosak233/cloudsdale/internal/cache" "github.com/elabosak233/cloudsdale/internal/controller" "github.com/elabosak233/cloudsdale/internal/extension/casbin" "github.com/elabosak233/cloudsdale/internal/extension/container/provider" - "github.com/elabosak233/cloudsdale/internal/global" + "github.com/elabosak233/cloudsdale/internal/extension/files" "github.com/elabosak233/cloudsdale/internal/middleware" "github.com/elabosak233/cloudsdale/internal/repository" "github.com/elabosak233/cloudsdale/internal/router" "github.com/elabosak233/cloudsdale/internal/service" + "github.com/elabosak233/cloudsdale/internal/utils" "github.com/elabosak233/cloudsdale/internal/utils/convertor" "github.com/elabosak233/cloudsdale/internal/utils/validator" "github.com/gin-contrib/cors" @@ -32,15 +33,15 @@ import ( ) func init() { - data, _ := assets.ReadStaticFile("banner.txt") + data, _ := files.FS.ReadFile("statics/banner.txt") banner := string(data) t, _ := template.New("cloudsdale").Parse(banner) _ = t.Execute(os.Stdout, struct { Version string Commit string }{ - Version: global.GitTag, - Commit: global.GitCommitID, + Version: utils.GitTag, + Commit: utils.GitCommitID, }) } @@ -48,10 +49,10 @@ func Run() { // Initialize the application logger.InitLogger() config.InitConfig() - assets.InitAssets() db.InitDatabase() casbin.InitCasbin() provider.InitContainerProvider() + cache.InitCache() // Debug mode isDebug := convertor.ToBoolD(os.Getenv("DEBUG"), false) diff --git a/internal/app/assets/assets.go b/internal/app/assets/assets.go deleted file mode 100644 index 6d0894cb..00000000 --- a/internal/app/assets/assets.go +++ /dev/null @@ -1,32 +0,0 @@ -package assets - -import ( - "fmt" - "github.com/elabosak233/cloudsdale/internal/app/config" - "github.com/elabosak233/cloudsdale/internal/extension/files" - "os" -) - -func InitAssets() { - if _, err := os.Stat(config.AppCfg().Gin.Paths.Assets); err != nil { - err = os.Mkdir(config.AppCfg().Gin.Paths.Assets, os.ModePerm) - } -} - -func ReadStaticFile(filename string) (data []byte, err error) { - if _, err = os.Stat(fmt.Sprintf("%s/statics/%s", config.AppCfg().Gin.Paths.Assets, filename)); err == nil { - data, err = os.ReadFile(fmt.Sprintf("%s/statics/%s", config.AppCfg().Gin.Paths.Assets, filename)) - } else { - data, err = files.FS.ReadFile("statics/" + filename) - } - return data, err -} - -func ReadTemplateFile(filename string) (data []byte, err error) { - if _, err = os.Stat(fmt.Sprintf("%s/templates/%s", config.AppCfg().Gin.Paths.Assets, filename)); err == nil { - data, err = os.ReadFile(fmt.Sprintf("%s/templates/%s", config.AppCfg().Gin.Paths.Assets, filename)) - } else { - data, err = files.FS.ReadFile("templates/" + filename) - } - return data, err -} diff --git a/internal/app/config/application.go b/internal/app/config/application.go index 0dbd2644..95a11f6d 100644 --- a/internal/app/config/application.go +++ b/internal/app/config/application.go @@ -27,6 +27,15 @@ type ApplicationCfg struct { Jwt struct { Expiration int `yaml:"expiration" json:"expiration" mapstructure:"expiration"` } `yaml:"jwt" json:"jwt" mapstructure:"jwt"` + Cache struct { + Provider string `yaml:"provider" json:"provider" mapstructure:"provider"` + Redis struct { + Host string `yaml:"host" json:"host" mapstructure:"host"` + Port int `yaml:"port" json:"port" mapstructure:"port"` + Password string `yaml:"password" json:"password" mapstructure:"password"` + DB int `yaml:"db" json:"db" mapstructure:"db"` + } `yaml:"redis" json:"redis" mapstructure:"redis"` + } `yaml:"cache" json:"cache" mapstructure:"cache"` Paths struct { Assets string `yaml:"assets" json:"assets" mapstructure:"assets"` Media string `yaml:"media" json:"media" mapstructure:"media"` @@ -55,7 +64,7 @@ type ApplicationCfg struct { SecretKey string `yaml:"secret_key" json:"secret_key" mapstructure:"secret_key"` } `yaml:"turnstile" json:"turnstile" mapstructure:"turnstile"` } `yaml:"captcha" json:"captcha" mapstructure:"captcha"` - Db struct { + DB struct { Provider string `yaml:"provider" json:"provider" mapstructure:"provider"` Postgres struct { Host string `yaml:"host" json:"host" mapstructure:"host"` diff --git a/internal/app/config/config.go b/internal/app/config/config.go index 1741cdee..8780aa16 100644 --- a/internal/app/config/config.go +++ b/internal/app/config/config.go @@ -21,7 +21,5 @@ func InitConfig() { InitApplicationCfg() InitPlatformCfg() - InitSignatureCfg() - jwtSecretKey = uuid.NewString() } diff --git a/internal/app/config/signature.go b/internal/app/config/signature.go deleted file mode 100644 index 3a4bbe85..00000000 --- a/internal/app/config/signature.go +++ /dev/null @@ -1,59 +0,0 @@ -package config - -import ( - "crypto/ed25519" - "encoding/base64" - "github.com/spf13/viper" - "go.uber.org/zap" - "os" - "path" - "reflect" -) - -var ( - v3 *viper.Viper - sigCfg SignatureCfg -) - -type SignatureCfg struct { - PublicKey string `yaml:"pub" json:"pub" mapstructure:"pub"` - PrivateKey string `yaml:"pem" json:"pem " mapstructure:"pem"` -} - -func SigCfg() *SignatureCfg { - return &sigCfg -} - -func InitSignatureCfg() { - v3 = viper.New() - configFile := path.Join("configs", "signature.json") - v3.SetConfigType("json") - v3.SetConfigFile(configFile) - - if _, err := os.Stat(configFile); err != nil { - publicKey, privateKey, _ := ed25519.GenerateKey(nil) - sigCfg.PrivateKey = base64.StdEncoding.EncodeToString(privateKey) - sigCfg.PublicKey = base64.StdEncoding.EncodeToString(publicKey) - _ = sigCfg.Save() - } - if err := v3.ReadInConfig(); err != nil { - zap.L().Fatal("Unable to read configuration file.", zap.Error(err)) - return - } - - if err := v3.Unmarshal(&sigCfg); err != nil { - zap.L().Error("Unable to parse configuration file to structure.") - } -} - -func (s *SignatureCfg) Save() (err error) { - val := reflect.ValueOf(sigCfg) - typeOfCfg := val.Type() - - for i := 0; i < val.NumField(); i++ { - field := val.Field(i) - v3.Set(typeOfCfg.Field(i).Tag.Get("mapstructure"), field.Interface()) - } - err = v3.WriteConfig() - return err -} diff --git a/internal/app/db/db.go b/internal/app/db/db.go index b3d5d66c..a97a7a6e 100644 --- a/internal/app/db/db.go +++ b/internal/app/db/db.go @@ -46,30 +46,30 @@ func Debug() { // If an error occurs during the connection, the program will exit. func initDatabaseEngine() { var err error - switch config.AppCfg().Db.Provider { + switch config.AppCfg().DB.Provider { case "postgres": dbInfo = fmt.Sprintf( "host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", - config.AppCfg().Db.Postgres.Host, - config.AppCfg().Db.Postgres.Port, - config.AppCfg().Db.Postgres.Username, - config.AppCfg().Db.Postgres.Password, - config.AppCfg().Db.Postgres.Dbname, - config.AppCfg().Db.Postgres.Sslmode, + config.AppCfg().DB.Postgres.Host, + config.AppCfg().DB.Postgres.Port, + config.AppCfg().DB.Postgres.Username, + config.AppCfg().DB.Postgres.Password, + config.AppCfg().DB.Postgres.Dbname, + config.AppCfg().DB.Postgres.Sslmode, ) db, err = gorm.Open(postgres.Open(dbInfo), &gorm.Config{}) case "mysql": dbInfo = fmt.Sprintf( "%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", - config.AppCfg().Db.MySQL.Username, - config.AppCfg().Db.MySQL.Password, - config.AppCfg().Db.MySQL.Host, - config.AppCfg().Db.MySQL.Port, - config.AppCfg().Db.MySQL.Dbname, + config.AppCfg().DB.MySQL.Username, + config.AppCfg().DB.MySQL.Password, + config.AppCfg().DB.MySQL.Host, + config.AppCfg().DB.MySQL.Port, + config.AppCfg().DB.MySQL.Dbname, ) db, err = gorm.Open(mysql.Open(dbInfo), &gorm.Config{}) case "sqlite": - dbInfo = config.AppCfg().Db.SQLite.Filename + dbInfo = config.AppCfg().DB.SQLite.Filename db, err = gorm.Open(sqlite.Open(dbInfo), &gorm.Config{}) } if err != nil { @@ -88,7 +88,6 @@ func migrate() { &model.UserTeam{}, &model.Submission{}, &model.Nat{}, - &model.Hint{}, &model.Pod{}, &model.Game{}, &model.GameChallenge{}, diff --git a/internal/cache/cache.go b/internal/cache/cache.go index cf38e38b..8c8f6b6f 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -1,10 +1,34 @@ package cache +import ( + "github.com/elabosak233/cloudsdale/internal/app/config" + "sync" + "time" +) + +var ( + cache ICache + onceCache sync.Once +) + type ICache interface { - Get(key string) (value string, err error) - Set(key string, value string, expire int) (err error) + Get(key string) (interface{}, bool) + Set(key string, value interface{}, expiration time.Duration) + Delete(key string) + DeleteByPrefix(prefix string) +} + +func C() ICache { + return cache } -func NewCache() ICache { - return nil +func InitCache() { + onceCache.Do(func() { + switch config.AppCfg().Gin.Cache.Provider { + case "memory": + cache = NewMemoryCache() + case "redis": + cache = NewRedisCache() + } + }) } diff --git a/internal/cache/memory.go b/internal/cache/memory.go index 6e8aa2cb..ea5ad2fc 100644 --- a/internal/cache/memory.go +++ b/internal/cache/memory.go @@ -1,7 +1,44 @@ package cache -type MemoryCache struct{} +import ( + goCache "github.com/patrickmn/go-cache" + "go.uber.org/zap" + "strings" + "time" +) + +type MemoryCache struct { + gc *goCache.Cache +} func NewMemoryCache() ICache { - return nil + gc := goCache.New(5*time.Minute, 10*time.Minute) + zap.L().Info("Cache module inits successfully. Using memory as cache provider.") + return &MemoryCache{ + gc: gc, + } +} +func (c *MemoryCache) Get(key string) (interface{}, bool) { + value, exist := c.gc.Get(key) + if exist { + zap.L().Info("Cache hit", zap.String("key", key)) + } + return value, exist +} + +func (c *MemoryCache) Set(key string, value interface{}, expiration time.Duration) { + zap.L().Info("Cache set", zap.String("key", key)) + c.gc.Set(key, value, expiration) +} + +func (c *MemoryCache) Delete(key string) { + c.gc.Delete(key) +} + +func (c *MemoryCache) DeleteByPrefix(prefix string) { + for k := range c.gc.Items() { + if strings.HasPrefix(k, prefix) { + c.gc.Delete(k) + } + } } diff --git a/internal/cache/redis.go b/internal/cache/redis.go index 3008aab1..c9595967 100644 --- a/internal/cache/redis.go +++ b/internal/cache/redis.go @@ -1,7 +1,97 @@ package cache -type RedisCache struct{} +import ( + "context" + "encoding/json" + "errors" + "fmt" + "github.com/elabosak233/cloudsdale/internal/app/config" + "github.com/gin-gonic/gin" + "github.com/redis/go-redis/v9" + "go.uber.org/zap" + "time" +) + +type RedisCache struct { + ctx context.Context + rdb *redis.Client +} func NewRedisCache() ICache { - return nil + rdb := redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%d", config.AppCfg().Gin.Cache.Redis.Host, config.AppCfg().Gin.Cache.Redis.Port), + Password: config.AppCfg().Gin.Cache.Redis.Password, + DB: config.AppCfg().Gin.Cache.Redis.DB, + }) + zap.L().Info("Cache module inits successfully. Using Redis as cache provider.") + return &RedisCache{ + ctx: context.Background(), + rdb: rdb, + } +} + +func (r *RedisCache) Set(key string, value interface{}, expiration time.Duration) { + h, ok := value.(gin.H) + if !ok { + zap.L().Error("Value is not of type gin.H", zap.Any("value", value)) + return + } + + jsonData, err := json.Marshal(h) + if err != nil { + zap.L().Error("Error marshalling gin.H to JSON", zap.Error(err)) + return + } + + if err := r.rdb.Set(r.ctx, key, jsonData, expiration).Err(); err != nil { + zap.L().Error("Error setting cache", zap.String("key", key), zap.Error(err)) + } + zap.L().Info("Cache set", zap.String("key", key)) +} + +func (r *RedisCache) Get(key string) (interface{}, bool) { + jsonData, err := r.rdb.Get(r.ctx, key).Result() + if errors.Is(err, redis.Nil) { + zap.L().Info("Cache miss", zap.String("key", key)) + return nil, false + } else if err != nil { + zap.L().Error("Error retrieving from cache", zap.String("key", key), zap.Error(err)) + return nil, false + } + + var h gin.H + if err := json.Unmarshal([]byte(jsonData), &h); err != nil { + zap.L().Error("Error unmarshalling JSON to gin.H", zap.Error(err)) + return nil, false + } + + zap.L().Info("Cache hit", zap.String("key", key)) + return h, true +} + +func (r *RedisCache) Delete(key string) { + if err := r.rdb.Del(r.ctx, key).Err(); err != nil { + zap.L().Error("Error deleting from cache", zap.String("key", key), zap.Error(err)) + } +} + +func (r *RedisCache) DeleteByPrefix(prefix string) { + var cursor uint64 + var keys []string + var err error + for { + keys, cursor, err = r.rdb.Scan(r.ctx, cursor, fmt.Sprintf("%s*", prefix), 10).Result() + if err != nil { + zap.L().Error("Error scanning cache for prefix", zap.String("prefix", prefix), zap.Error(err)) + break + } + if len(keys) > 0 { + if err := r.rdb.Del(r.ctx, keys...).Err(); err != nil { + zap.L().Error("Error deleting keys by prefix", zap.String("prefix", prefix), zap.Error(err)) + } + } + if cursor == 0 { + break + } + } } diff --git a/internal/controller/challenge.go b/internal/controller/challenge.go index 02eba49e..af7271a4 100644 --- a/internal/controller/challenge.go +++ b/internal/controller/challenge.go @@ -1,29 +1,24 @@ package controller import ( + "fmt" + "github.com/elabosak233/cloudsdale/internal/cache" "github.com/elabosak233/cloudsdale/internal/model" "github.com/elabosak233/cloudsdale/internal/model/request" "github.com/elabosak233/cloudsdale/internal/service" + "github.com/elabosak233/cloudsdale/internal/utils" "github.com/elabosak233/cloudsdale/internal/utils/convertor" "github.com/elabosak233/cloudsdale/internal/utils/validator" "github.com/gin-gonic/gin" "net/http" + "time" ) -type IHintController interface { - Create(ctx *gin.Context) - Update(ctx *gin.Context) - Delete(ctx *gin.Context) -} - type IChallengeController interface { Find(ctx *gin.Context) Create(ctx *gin.Context) Update(ctx *gin.Context) Delete(ctx *gin.Context) - CreateHint(ctx *gin.Context) - UpdateHint(ctx *gin.Context) - DeleteHint(ctx *gin.Context) CreateFlag(ctx *gin.Context) UpdateFlag(ctx *gin.Context) DeleteFlag(ctx *gin.Context) @@ -35,7 +30,6 @@ type IChallengeController interface { type ChallengeController struct { challengeService service.IChallengeService flagService service.IFlagService - hintService service.IHintService mediaService service.IMediaService } @@ -43,7 +37,6 @@ func NewChallengeController(appService *service.Service) IChallengeController { return &ChallengeController{ challengeService: appService.ChallengeService, flagService: appService.FlagService, - hintService: appService.HintService, mediaService: appService.MediaService, } } @@ -78,12 +71,21 @@ func (c *ChallengeController) Find(ctx *gin.Context) { challengeFindRequest.UserID = user.ID challengeFindRequest.IsDetailed = &isDetailed challengeFindRequest.IsPracticable = isPracticable() - challenges, total, _ := c.challengeService.Find(challengeFindRequest) - ctx.JSON(http.StatusOK, gin.H{ - "code": http.StatusOK, - "total": total, - "data": challenges, - }) + value, exist := cache.C().Get(fmt.Sprintf("challenges:%s", utils.HashStruct(challengeFindRequest))) + if !exist { + challenges, total, _ := c.challengeService.Find(challengeFindRequest) + value = gin.H{ + "code": http.StatusOK, + "total": total, + "data": challenges, + } + cache.C().Set( + fmt.Sprintf("challenges:%s", utils.HashStruct(challengeFindRequest)), + value, + 5*time.Minute, + ) + } + ctx.JSON(http.StatusOK, value) } // Create @@ -166,95 +168,6 @@ func (c *ChallengeController) Delete(ctx *gin.Context) { }) } -// CreateHint -// @Summary 创建提示 -// @Description -// @Tags Challenge -// @Accept json -// @Produce json -// @Security ApiKeyAuth -// @Router /challenges/{id}/hints [post] -func (c *ChallengeController) CreateHint(ctx *gin.Context) { - hintCreateRequest := request.HintCreateRequest{} - err := ctx.ShouldBindJSON(&hintCreateRequest) - if err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{ - "code": http.StatusBadRequest, - "msg": validator.GetValidMsg(err, &hintCreateRequest), - }) - return - } - hintCreateRequest.ChallengeID = convertor.ToUintD(ctx.Param("id"), 0) - err = c.hintService.Create(hintCreateRequest) - if err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{ - "code": http.StatusBadRequest, - "msg": err.Error(), - }) - return - } - ctx.JSON(http.StatusOK, gin.H{ - "code": http.StatusOK, - }) -} - -// UpdateHint -// @Summary 更新提示 -// @Description -// @Tags Challenge -// @Accept json -// @Produce json -// @Security ApiKeyAuth -// @Router /challenges/{id}/hints/{hint_id} [put] -func (c *ChallengeController) UpdateHint(ctx *gin.Context) { - hintUpdateRequest := request.HintUpdateRequest{} - err := ctx.ShouldBindJSON(&hintUpdateRequest) - if err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{ - "code": http.StatusBadRequest, - "msg": validator.GetValidMsg(err, &hintUpdateRequest), - }) - return - } - hintUpdateRequest.ID = convertor.ToUintD(ctx.Param("hint_id"), 0) - hintUpdateRequest.ChallengeID = convertor.ToUintD(ctx.Param("id"), 0) - err = c.hintService.Update(hintUpdateRequest) - if err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{ - "code": http.StatusBadRequest, - "msg": err.Error(), - }) - return - } - ctx.JSON(http.StatusOK, gin.H{ - "code": http.StatusOK, - }) -} - -// DeleteHint -// @Summary 删除提示 -// @Description -// @Tags Challenge -// @Accept json -// @Produce json -// @Security ApiKeyAuth -// @Router /challenges/{id}/hints/{hint_id} [delete] -func (c *ChallengeController) DeleteHint(ctx *gin.Context) { - hintDeleteRequest := request.HintDeleteRequest{} - hintDeleteRequest.ID = convertor.ToUintD(ctx.Param("hint_id"), 0) - err := c.hintService.Delete(hintDeleteRequest) - if err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{ - "code": http.StatusBadRequest, - "msg": err.Error(), - }) - return - } - ctx.JSON(http.StatusOK, gin.H{ - "code": http.StatusOK, - }) -} - // CreateFlag // @Summary 创建 flag // @Description diff --git a/internal/extension/container/manager/k8s.go b/internal/extension/container/manager/k8s.go index 839a666c..ce9c469d 100644 --- a/internal/extension/container/manager/k8s.go +++ b/internal/extension/container/manager/k8s.go @@ -8,7 +8,7 @@ import ( "github.com/elabosak233/cloudsdale/internal/app/config" "github.com/elabosak233/cloudsdale/internal/extension/container/provider" "github.com/elabosak233/cloudsdale/internal/model" - "github.com/elabosak233/cloudsdale/internal/utils/generator" + "github.com/elabosak233/cloudsdale/internal/utils" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -59,7 +59,7 @@ func (c *K8sManager) Setup() (nats []*model.Nat, err error) { } // Add the flag information to the environment variables envs = append(envs, corev1.EnvVar{Name: c.flag.Env, Value: c.flag.Value}) - uid := generator.HyphenlessUUID() + uid := utils.HyphenlessUUID() containers = append(containers, corev1.Container{ Name: uid, Image: c.challenge.ImageName, diff --git a/internal/extension/files/configs/application.json b/internal/extension/files/configs/application.json index e821c5db..3beab0aa 100644 --- a/internal/extension/files/configs/application.json +++ b/internal/extension/files/configs/application.json @@ -7,6 +7,15 @@ "jwt": { "expiration": 180 }, + "cache": { + "provider": "memory", + "redis": { + "host": "cache", + "port": 6379, + "password": "", + "db": 0 + } + }, "paths": { "media": "./media", "assets": "./assets" diff --git a/internal/model/challenge.go b/internal/model/challenge.go index 8c02bdd4..484dfa43 100644 --- a/internal/model/challenge.go +++ b/internal/model/challenge.go @@ -25,7 +25,6 @@ type Challenge struct { CPULimit int64 `gorm:"default:1" json:"cpu_limit,omitempty"` // The challenge's CPU limit. (0 means no limit) MemoryLimit int64 `gorm:"default:64" json:"memory_limit,omitempty"` // The challenge's memory limit. (0 means no limit) Flags []*Flag `json:"flags,omitempty"` - Hints []*Hint `json:"hints,omitempty"` Ports []*Port `json:"ports,omitempty"` Envs []*Env `json:"envs,omitempty"` Solved *Submission `json:"solved,omitempty"` @@ -73,7 +72,6 @@ func (c *Challenge) BeforeUpdate(db *gorm.DB) (err error) { func (c *Challenge) BeforeDelete(db *gorm.DB) (err error) { db.Table("flags").Where("challenge_id = ?", c.ID).Delete(&Flag{}) - db.Table("hints").Where("challenge_id = ?", c.ID).Delete(&Hint{}) db.Table("ports").Where("challenge_id = ?", c.ID).Delete(&Port{}) db.Table("envs").Where("challenge_id = ?", c.ID).Delete(&Env{}) db.Table("submissions").Where("challenge_id = ?", c.ID).Delete(&Submission{}) diff --git a/internal/model/hint.go b/internal/model/hint.go deleted file mode 100644 index 08d6f923..00000000 --- a/internal/model/hint.go +++ /dev/null @@ -1,11 +0,0 @@ -package model - -type Hint struct { - ID uint `json:"id"` // The hint's id. - ChallengeID uint `gorm:"not null;" json:"challenge_id"` // The challenge which the hint belongs to. - Challenge *Challenge `json:"challenge"` // The challenge which the hint belongs to. - Content string `gorm:"type:text;not null;" json:"content"` // The content of the hint. - PublishedAt int64 `gorm:"not null;" json:"published_at"` // When the hint will be published. - CreatedAt int64 `gorm:"autoUpdateTime:milli" json:"created_at"` // The hint's creation time. - UpdatedAt int64 `gorm:"autoUpdateTime:milli" json:"updated_at"` // The hint's last update time. -} diff --git a/internal/model/nat.go b/internal/model/nat.go index 176d1871..a5d9c212 100644 --- a/internal/model/nat.go +++ b/internal/model/nat.go @@ -4,8 +4,8 @@ type Nat struct { ID uint `json:"id"` PodID uint `gorm:"not null" json:"pod_id"` Pod *Pod `json:"pod,omitempty"` - SrcPort int `gorm:"not null" json:"src_port"` // Of Image - DstPort int `gorm:"not null" json:"dst_port"` // Of Pod - Proxy string `json:"proxy"` // Of Platform + SrcPort int `gorm:"not null" json:"src_port"` // Of image + DstPort int `gorm:"not null" json:"dst_port"` // Of pod + Proxy string `json:"proxy"` // Of platform Entry string `gorm:"type:varchar(128)" json:"entry"` } diff --git a/internal/model/port.go b/internal/model/port.go index 2aa7a4b5..dfb57d79 100644 --- a/internal/model/port.go +++ b/internal/model/port.go @@ -1,6 +1,6 @@ package model -// Port is the mapping between the JeopardyImage and the exposed port of the JeopardyImage. +// Port is the mapping between the JeopardyImage and the exposed port of the image. // Because of the port is only a subsidiary table, it doesn't need the creation time or updated time. type Port struct { ID uint `json:"id"` // The port's id. As primary key. diff --git a/internal/model/request/challenge_request.go b/internal/model/request/challenge_request.go index 6d3d21d2..3f0df798 100644 --- a/internal/model/request/challenge_request.go +++ b/internal/model/request/challenge_request.go @@ -1,6 +1,8 @@ package request -import "github.com/elabosak233/cloudsdale/internal/model" +import ( + "github.com/elabosak233/cloudsdale/internal/model" +) type ChallengeCreateRequest struct { Title string `json:"title"` diff --git a/internal/model/team.go b/internal/model/team.go index bd2dd744..18059183 100644 --- a/internal/model/team.go +++ b/internal/model/team.go @@ -25,6 +25,7 @@ type Team struct { func (t *Team) Simplify() { t.InviteToken = "" + t.Description = "" } func (t *Team) AfterFind(db *gorm.DB) (err error) { diff --git a/internal/model/user.go b/internal/model/user.go index 995f356f..a707a9f3 100644 --- a/internal/model/user.go +++ b/internal/model/user.go @@ -3,11 +3,9 @@ package model import ( "fmt" "github.com/elabosak233/cloudsdale/internal/app/config" - "github.com/elabosak233/cloudsdale/internal/utils/signature" "gorm.io/gorm" "os" "path" - "strconv" ) type User struct { @@ -17,7 +15,6 @@ type User struct { Description string `gorm:"column:description;type:text" json:"description"` // The user's description. Email string `gorm:"column:email;varchar(64);unique;not null" json:"email,omitempty"` // The user's email. Avatar *File `gorm:"-" json:"avatar"` // The user's avatar. - Signature string `gorm:"column:signature;varchar(255);unique;" json:"signature,omitempty"` // The user's signature. Group string `gorm:"column:group;varchar(16);not null;" json:"group,omitempty"` // The user's group. Password string `gorm:"column:password;type:varchar(255);not null" json:"password,omitempty"` // The user's password. Crypt. CreatedAt int64 `gorm:"autoUpdateTime:milli" json:"created_at,omitempty"` // The user's creation time. @@ -27,6 +24,7 @@ type User struct { func (u *User) Simplify() { u.Password = "" + u.Description = "" } func (u *User) AfterFind(db *gorm.DB) (err error) { @@ -49,14 +47,6 @@ func (u *User) AfterFind(db *gorm.DB) (err error) { return nil } -// AfterCreate Hook -// Since the PrivateKey used here belongs to the entire Cloudsdale, it relies on GORM Hooks to write the Signature. -func (u *User) AfterCreate(db *gorm.DB) (err error) { - sig, _ := signature.Sign(config.SigCfg().PrivateKey, strconv.Itoa(int(u.ID))) - u.Signature = fmt.Sprintf("%s:%s", strconv.Itoa(int(u.ID)), sig) - return db.Table("users").Updates(&u).Error -} - func (u *User) BeforeDelete(db *gorm.DB) (err error) { db.Table("user_teams").Where("user_id = ?", u.ID).Delete(&UserTeam{}) return nil diff --git a/internal/repository/category.go b/internal/repository/category.go index 370c45e4..4d9641fa 100644 --- a/internal/repository/category.go +++ b/internal/repository/category.go @@ -17,7 +17,7 @@ type CategoryRepository struct { db *gorm.DB } -func NewCategoryRepositoryImpl(db *gorm.DB) ICategoryRepository { +func NewCategoryRepository(db *gorm.DB) ICategoryRepository { return &CategoryRepository{db: db} } diff --git a/internal/repository/challenge.go b/internal/repository/challenge.go index a0d3eec2..2f26f3a3 100644 --- a/internal/repository/challenge.go +++ b/internal/repository/challenge.go @@ -7,10 +7,10 @@ import ( ) type IChallengeRepository interface { - Create(challenge model.Challenge) (c model.Challenge, err error) - Update(challenge model.Challenge) (c model.Challenge, err error) - Delete(id uint) (err error) - Find(req request.ChallengeFindRequest) (challenges []model.Challenge, total int64, err error) + Create(challenge model.Challenge) (model.Challenge, error) + Update(challenge model.Challenge) (model.Challenge, error) + Delete(id uint) error + Find(req request.ChallengeFindRequest) ([]model.Challenge, int64, error) } type ChallengeRepository struct { diff --git a/internal/repository/hint.go b/internal/repository/hint.go deleted file mode 100644 index 32bfe04c..00000000 --- a/internal/repository/hint.go +++ /dev/null @@ -1,35 +0,0 @@ -package repository - -import ( - "github.com/elabosak233/cloudsdale/internal/model" - "gorm.io/gorm" -) - -type IHintRepository interface { - Create(hint model.Hint) (h model.Hint, err error) - Update(hint model.Hint) (h model.Hint, err error) - Delete(hint model.Hint) (err error) -} - -type HintRepository struct { - db *gorm.DB -} - -func NewHintRepository(db *gorm.DB) IHintRepository { - return &HintRepository{db: db} -} - -func (t *HintRepository) Create(hint model.Hint) (h model.Hint, err error) { - result := t.db.Table("hints").Create(&hint) - return hint, result.Error -} - -func (t *HintRepository) Update(hint model.Hint) (h model.Hint, err error) { - result := t.db.Table("hints").Model(&hint).Updates(&hint) - return hint, result.Error -} - -func (t *HintRepository) Delete(hint model.Hint) (err error) { - result := t.db.Table("hints").Delete(&hint) - return result.Error -} diff --git a/internal/repository/repository.go b/internal/repository/repository.go index 4209ec6f..37fa1985 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -27,7 +27,6 @@ type Repository struct { EnvRepository IEnvRepository FlagGenRepository IFlagGenRepository GameTeamRepository IGameTeamRepository - HintRepository IHintRepository NoticeRepository INoticeRepository } @@ -48,14 +47,13 @@ func InitRepository() { GameRepository: NewGameRepository(db), UserTeamRepository: NewUserTeamRepository(db), GameChallengeRepository: NewGameChallengeRepository(db), - CategoryRepository: NewCategoryRepositoryImpl(db), + CategoryRepository: NewCategoryRepository(db), FlagRepository: NewFlagRepository(db), PortRepository: NewPortRepository(db), NatRepository: NewNatRepository(db), EnvRepository: NewEnvRepository(db), FlagGenRepository: NewFlagGenRepository(db), GameTeamRepository: NewGameTeamRepository(db), - HintRepository: NewHintRepository(db), NoticeRepository: NewNoticeRepository(db), } }) diff --git a/internal/router/challenge.go b/internal/router/challenge.go index a5992ab6..7464004d 100644 --- a/internal/router/challenge.go +++ b/internal/router/challenge.go @@ -28,9 +28,6 @@ func (c *ChallengeRouter) Register() { c.router.POST("/", c.controller.Create) c.router.PUT("/:id", c.controller.Update) c.router.DELETE("/:id", c.controller.Delete) - c.router.POST("/:id/hints", c.controller.CreateHint) - c.router.PUT("/:id/hints/:hint_id", c.controller.UpdateHint) - c.router.DELETE("/:id/hints/:hint_id", c.controller.DeleteHint) c.router.POST("/:id/flags", c.controller.CreateFlag) c.router.PUT("/:id/flags/:flag_id", c.controller.UpdateFlag) c.router.DELETE("/:id/flags/:flag_id", c.controller.DeleteFlag) diff --git a/internal/router/router.go b/internal/router/router.go index 545d838a..acacc7b3 100644 --- a/internal/router/router.go +++ b/internal/router/router.go @@ -29,6 +29,7 @@ func InitRouter( "msg": "This is the heart of Cloudsdale.", }) }) + NewUserRouter(r.router.Group("/users"), r.controller.UserController).Register() NewChallengeRouter(r.router.Group("/challenges"), r.controller.ChallengeController).Register() NewPodRouter(r.router.Group("/pods"), r.controller.PodController).Register() diff --git a/internal/service/game_team.go b/internal/service/game_team.go index f4727540..97507659 100644 --- a/internal/service/game_team.go +++ b/internal/service/game_team.go @@ -6,8 +6,8 @@ import ( "github.com/elabosak233/cloudsdale/internal/model" "github.com/elabosak233/cloudsdale/internal/model/request" "github.com/elabosak233/cloudsdale/internal/repository" + "github.com/elabosak233/cloudsdale/internal/utils" "github.com/elabosak233/cloudsdale/internal/utils/calculate" - "github.com/elabosak233/cloudsdale/internal/utils/signature" "github.com/mitchellh/mapstructure" "strconv" ) @@ -141,8 +141,7 @@ func (g *GameTeamService) Create(req request.GameTeamCreateRequest) (err error) IsAllowed: &isAllowed, } - sig, _ := signature.Sign(game.PrivateKey, strconv.Itoa(int(team.ID))) - gameTeam.Signature = fmt.Sprintf("%s:%s", strconv.Itoa(int(team.ID)), sig) + gameTeam.Signature = fmt.Sprintf("%s:%s", strconv.Itoa(int(team.ID)), utils.HyphenlessUUID()) err = g.gameTeamRepository.Create(gameTeam) return err diff --git a/internal/service/hint.go b/internal/service/hint.go deleted file mode 100644 index 68afe2cf..00000000 --- a/internal/service/hint.go +++ /dev/null @@ -1,45 +0,0 @@ -package service - -import ( - "github.com/elabosak233/cloudsdale/internal/model" - "github.com/elabosak233/cloudsdale/internal/model/request" - "github.com/elabosak233/cloudsdale/internal/repository" - "github.com/mitchellh/mapstructure" -) - -type IHintService interface { - Create(req request.HintCreateRequest) (err error) - Update(req request.HintUpdateRequest) (err error) - Delete(req request.HintDeleteRequest) (err error) -} - -type HintService struct { - hintRepository repository.IHintRepository -} - -func NewHintService(appRepository *repository.Repository) IHintService { - return &HintService{ - hintRepository: appRepository.HintRepository, - } -} - -func (h *HintService) Create(req request.HintCreateRequest) (err error) { - var hint model.Hint - _ = mapstructure.Decode(req, &hint) - _, err = h.hintRepository.Create(hint) - return err -} - -func (h *HintService) Update(req request.HintUpdateRequest) (err error) { - var hint model.Hint - _ = mapstructure.Decode(req, &hint) - _, err = h.hintRepository.Update(hint) - return err -} - -func (h *HintService) Delete(req request.HintDeleteRequest) (err error) { - var hint model.Hint - _ = mapstructure.Decode(req, &hint) - err = h.hintRepository.Delete(hint) - return err -} diff --git a/internal/service/pod.go b/internal/service/pod.go index 50e619b1..c2cd0c9c 100644 --- a/internal/service/pod.go +++ b/internal/service/pod.go @@ -9,8 +9,9 @@ import ( "github.com/elabosak233/cloudsdale/internal/model/request" "github.com/elabosak233/cloudsdale/internal/model/response" "github.com/elabosak233/cloudsdale/internal/repository" + "github.com/elabosak233/cloudsdale/internal/utils" "github.com/elabosak233/cloudsdale/internal/utils/convertor" - "github.com/elabosak233/cloudsdale/internal/utils/generator" + "strings" "sync" "time" ) @@ -65,6 +66,11 @@ func NewPodService(appRepository *repository.Repository) IPodService { } } +func GenerateFlag(flagFmt string) (flag string) { + flag = strings.Replace(flagFmt, "[UUID]", utils.HyphenlessUUID(), -1) + return flag +} + func (t *PodService) IsLimited(userID uint, limit int64) (remainder int64) { if userID == 0 { return 0 @@ -133,7 +139,7 @@ func (t *PodService) Create(req request.PodCreateRequest) (res response.PodStatu for _, f := range challenge.Flags { if f.Type == "dynamic" { flag = *f - flag.Value = generator.GenerateFlag(flag.Value) + flag.Value = GenerateFlag(flag.Value) } else { if f.Env == "" { f.Env = "FLAG" diff --git a/internal/service/service.go b/internal/service/service.go index 11d33228..cd0d4cc0 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -26,7 +26,6 @@ type Service struct { GameTeamService IGameTeamService CategoryService ICategoryService FlagService IFlagService - HintService IHintService NoticeService INoticeService } @@ -53,7 +52,6 @@ func InitService() { GameTeamService: NewGameTeamService(appRepository), CategoryService: NewCategoryService(appRepository), FlagService: NewFlagService(appRepository), - HintService: NewHintService(appRepository), NoticeService: NewNoticeService(appRepository), } }) diff --git a/internal/service/user_team.go b/internal/service/user_team.go index a2cb404e..4a06b6d3 100644 --- a/internal/service/user_team.go +++ b/internal/service/user_team.go @@ -8,9 +8,9 @@ import ( ) type IUserTeamService interface { - Join(req request.TeamUserJoinRequest) (err error) - Create(req request.TeamUserCreateRequest) (err error) - Delete(req request.TeamUserDeleteRequest) (err error) + Join(req request.TeamUserJoinRequest) error + Create(req request.TeamUserCreateRequest) error + Delete(req request.TeamUserDeleteRequest) error } type UserTeamService struct { @@ -27,7 +27,7 @@ func NewUserTeamService(appRepository *repository.Repository) IUserTeamService { } } -func (t *UserTeamService) Join(req request.TeamUserJoinRequest) (err error) { +func (t *UserTeamService) Join(req request.TeamUserJoinRequest) error { user, err := t.userRepository.FindById(req.UserID) team, err := t.teamRepository.FindById(req.TeamID) if err != nil || user.ID == 0 || team.ID == 0 { @@ -43,7 +43,7 @@ func (t *UserTeamService) Join(req request.TeamUserJoinRequest) (err error) { return err } -func (t *UserTeamService) Create(req request.TeamUserCreateRequest) (err error) { +func (t *UserTeamService) Create(req request.TeamUserCreateRequest) error { user, err := t.userRepository.FindById(req.UserID) team, err := t.teamRepository.FindById(req.TeamID) if err != nil || user.ID == 0 || team.ID == 0 { @@ -56,7 +56,7 @@ func (t *UserTeamService) Create(req request.TeamUserCreateRequest) (err error) return err } -func (t *UserTeamService) Delete(req request.TeamUserDeleteRequest) (err error) { +func (t *UserTeamService) Delete(req request.TeamUserDeleteRequest) error { user, err := t.userRepository.FindById(req.UserID) team, err := t.teamRepository.FindById(req.TeamID) if err != nil || user.ID == 0 || team.ID == 0 { diff --git a/internal/global/const.go b/internal/utils/const.go similarity index 87% rename from internal/global/const.go rename to internal/utils/const.go index 8c7269c5..eced4115 100644 --- a/internal/global/const.go +++ b/internal/utils/const.go @@ -1,4 +1,4 @@ -package global +package utils // Need to be injected by -ldflags var ( diff --git a/internal/utils/generator/generator.go b/internal/utils/generator/generator.go deleted file mode 100644 index 6c267051..00000000 --- a/internal/utils/generator/generator.go +++ /dev/null @@ -1,15 +0,0 @@ -package generator - -import ( - "github.com/google/uuid" - "strings" -) - -func GenerateFlag(flagFmt string) (flag string) { - flag = strings.Replace(flagFmt, "[UUID]", uuid.NewString(), -1) - return flag -} - -func HyphenlessUUID() string { - return strings.Replace(uuid.NewString(), "-", "", -1) -} diff --git a/internal/utils/signature/signature.go b/internal/utils/signature/signature.go deleted file mode 100644 index 7bb47e04..00000000 --- a/internal/utils/signature/signature.go +++ /dev/null @@ -1,13 +0,0 @@ -package signature - -import ( - "crypto/ed25519" - "encoding/base64" -) - -func Sign(privateKey string, message string) (signature string, err error) { - pri, err := base64.StdEncoding.DecodeString(privateKey) - return base64.StdEncoding.EncodeToString( - ed25519.Sign(pri, []byte(message)), - ), err -} diff --git a/internal/utils/utils.go b/internal/utils/utils.go new file mode 100644 index 00000000..c8c470e5 --- /dev/null +++ b/internal/utils/utils.go @@ -0,0 +1,34 @@ +package utils + +import ( + "bytes" + "crypto/ed25519" + "crypto/sha256" + "encoding/base64" + "encoding/gob" + "fmt" + "github.com/google/uuid" + "strings" +) + +func Sign(privateKey string, message string) (signature string, err error) { + pri, err := base64.StdEncoding.DecodeString(privateKey) + return base64.StdEncoding.EncodeToString( + ed25519.Sign(pri, []byte(message)), + ), err +} + +func HyphenlessUUID() string { + return strings.Replace(uuid.NewString(), "-", "", -1) +} + +func HashStruct(s interface{}) string { + var buf bytes.Buffer + enc := gob.NewEncoder(&buf) + err := enc.Encode(s) + if err != nil { + return "null" + } + hash := sha256.Sum256(buf.Bytes()) + return fmt.Sprintf("%x", hash) +}