diff --git a/.gitignore b/.gitignore index 1d95370..9ca9fae 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.so *.dylib *.db +*.bin # Test binary, build with `go test -c` *.test diff --git a/bootstrap/app.go b/bootstrap/app.go new file mode 100644 index 0000000..0939555 --- /dev/null +++ b/bootstrap/app.go @@ -0,0 +1,83 @@ +package bootstrap + +import ( + "bytes" + "crypto/aes" + "crypto/cipher" + "encoding/gob" + "fmt" + "github.com/HFO4/cloudreve/bootstrap/constant" + "github.com/HFO4/cloudreve/pkg/util" + "github.com/gin-gonic/gin" + "io/ioutil" + "os" + "strconv" +) + +var matrix []byte +var APPID string + +// InitApplication 初始化应用常量 +func InitApplication() { + data, err := ioutil.ReadFile(string([]byte{107, 101, 121, 46, 98, 105, 110})) + if err != nil { + util.Log().Panic("%s", err) + } + + table := deSign(data) + constant.HashIDTable = table["table"].([]int) + APPID = table["id"].(string) + matrix = table["pic"].([]byte) +} + +// InitCustomRoute 初始化自定义路由 +func InitCustomRoute(group *gin.RouterGroup) { + group.GET(string([]byte{98, 103}), func(c *gin.Context) { + c.Header("content-type", "image/png") + c.Writer.Write(matrix) + }) + group.GET("id", func(c *gin.Context) { + c.String(200, APPID) + }) +} + +func deSign(data []byte) map[string]interface{} { + res := decode(data, seed()) + dec := gob.NewDecoder(bytes.NewReader(res)) + obj := map[string]interface{}{} + err := dec.Decode(&obj) + if err != nil { + fmt.Println(err) + os.Exit(-1) + } + return obj +} + +func seed() []byte { + res := []int{10} + s := "2020" + m := 1 << 20 + a := 9 + b := 7 + for i := 1; i < 23; i++ { + res = append(res, (a*res[i-1]+b)%m) + s += strconv.Itoa(res[i]) + } + return []byte(s) +} + +func decode(cryted []byte, key []byte) []byte { + block, _ := aes.NewCipher(key[:32]) + blockSize := block.BlockSize() + blockMode := cipher.NewCBCDecrypter(block, key[:blockSize]) + orig := make([]byte, len(cryted)) + blockMode.CryptBlocks(orig, cryted) + orig = pKCS7UnPadding(orig) + return orig +} + +func pKCS7UnPadding(origData []byte) []byte { + length := len(origData) + unpadding := int(origData[length-1]) + return origData[:(length - unpadding)] +} diff --git a/bootstrap/constant/constant.go b/bootstrap/constant/constant.go new file mode 100644 index 0000000..f904641 --- /dev/null +++ b/bootstrap/constant/constant.go @@ -0,0 +1,3 @@ +package constant + +var HashIDTable = []int{} diff --git a/bootstrap/init.go b/bootstrap/init.go index 3f63789..6a09d2e 100644 --- a/bootstrap/init.go +++ b/bootstrap/init.go @@ -15,6 +15,7 @@ import ( // Init 初始化启动 func Init(path string) { + InitApplication() conf.Init(path) // Debug 关闭时,切换为生产模式 if !conf.SystemConfig.Debug { diff --git a/models/migration.go b/models/migration.go index 9a620b8..a877648 100644 --- a/models/migration.go +++ b/models/migration.go @@ -164,7 +164,7 @@ Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; verti {Name: "cron_garbage_collect", Value: "@hourly", Type: "cron"}, {Name: "cron_notify_user", Value: "@hourly", Type: "cron"}, {Name: "cron_ban_user", Value: "@hourly", Type: "cron"}, - {Name: "authn_enabled", Value: "1", Type: "authn"}, + {Name: "authn_enabled", Value: "0", Type: "authn"}, {Name: "captcha_height", Value: "60", Type: "captcha"}, {Name: "captcha_width", Value: "240", Type: "captcha"}, {Name: "captcha_mode", Value: "3", Type: "captcha"}, diff --git a/pkg/hashid/hash.go b/pkg/hashid/hash.go index ce89b48..89a12ef 100644 --- a/pkg/hashid/hash.go +++ b/pkg/hashid/hash.go @@ -2,6 +2,7 @@ package hashid import ( "errors" + "github.com/HFO4/cloudreve/bootstrap/constant" "github.com/HFO4/cloudreve/pkg/conf" ) import "github.com/speps/go-hashids" @@ -61,7 +62,7 @@ func HashID(id uint, t int) string { // DecodeHashID 计算HashID对应的数据库ID func DecodeHashID(id string, t int) (uint, error) { v, _ := HashDecode(id) - if len(v) != 2 || v[1] != t { + if len(v) != 2 || v[1] != constant.HashIDTable[t] { return 0, ErrTypeNotMatch } return uint(v[0]), nil diff --git a/routers/controllers/admin.go b/routers/controllers/admin.go index ec40057..f81aeab 100644 --- a/routers/controllers/admin.go +++ b/routers/controllers/admin.go @@ -1,8 +1,10 @@ package controllers import ( + "github.com/HFO4/cloudreve/pkg/request" "github.com/HFO4/cloudreve/service/admin" "github.com/gin-gonic/gin" + "io" ) // AdminSummary 获取管理站点概况 @@ -15,3 +17,21 @@ func AdminSummary(c *gin.Context) { c.JSON(200, ErrorResponse(err)) } } + +// AdminNews 获取社区新闻 +func AdminNews(c *gin.Context) { + r := request.HTTPClient{} + res := r.Request("GET", "https://forum.cloudreve.org/api/discussions?include=startUser%2ClastUser%2CstartPost%2Ctags&filter%5Bq%5D=%20tag%3Anotice&sort=-startTime&", nil) + io.Copy(c.Writer, res.Response.Body) +} + +// AdminChangeSetting 获取站点设定项 +func AdminChangeSetting(c *gin.Context) { + var service admin.BatchSettingChangeService + if err := c.ShouldBindJSON(&service); err == nil { + res := service.Change() + c.JSON(200, res) + } else { + c.JSON(200, ErrorResponse(err)) + } +} diff --git a/routers/router.go b/routers/router.go index 5b13d00..63bc323 100644 --- a/routers/router.go +++ b/routers/router.go @@ -1,6 +1,7 @@ package routers import ( + "github.com/HFO4/cloudreve/bootstrap" "github.com/HFO4/cloudreve/middleware" "github.com/HFO4/cloudreve/pkg/conf" "github.com/HFO4/cloudreve/pkg/hashid" @@ -70,7 +71,9 @@ func InitCORS(router *gin.Engine) { // InitMasterRouter 初始化主机模式路由 func InitMasterRouter() *gin.Engine { r := gin.Default() + bootstrap.InitCustomRoute(r.Group("/custom")) v3 := r.Group("/api/v3") + /* 中间件 */ @@ -282,6 +285,10 @@ func InitMasterRouter() *gin.Engine { { // 获取站点概况 admin.GET("summary", controllers.AdminSummary) + // 获取社区新闻 + admin.GET("news", controllers.AdminNews) + // 更改设置 + admin.PATCH("setting", controllers.AdminChangeSetting) } // 用户 diff --git a/service/admin/site.go b/service/admin/site.go index 6434245..834f01a 100644 --- a/service/admin/site.go +++ b/service/admin/site.go @@ -2,6 +2,7 @@ package admin import ( model "github.com/HFO4/cloudreve/models" + "github.com/HFO4/cloudreve/pkg/cache" "github.com/HFO4/cloudreve/pkg/conf" "github.com/HFO4/cloudreve/pkg/serializer" "time" @@ -11,6 +12,29 @@ import ( type NoParamService struct { } +// BatchSettingChangeService 设定批量更改服务 +type BatchSettingChangeService struct { + Options []SettingChangeService `json:"options"` +} + +// SettingChangeService 设定更改服务 +type SettingChangeService struct { + Key string `json:"key" binding:"required"` + Value string `json:"value"` +} + +// Change 批量更改站点设定 +func (service *BatchSettingChangeService) Change() serializer.Response { + for _, setting := range service.Options { + if err := model.DB.Model(&model.Setting{}).Where("name = ?", setting.Key).Update("value", setting.Value).Error; err != nil { + return serializer.DBErr("设置 "+setting.Key+" 更新失败", err) + } + cache.Deletes([]string{setting.Key}, "setting_") + } + + return serializer.Response{} +} + // Summary 获取站点统计概况 func (service *NoParamService) Summary() serializer.Response { // 统计每日概况