♻️ Bazaar adds parameter validation (#17132)

This commit is contained in:
Jeffrey Chen 2026-03-04 20:48:12 +08:00 committed by GitHub
parent d03ebdec82
commit 17d49b481f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 162 additions and 73 deletions

View file

@ -25,6 +25,14 @@ import (
"github.com/siyuan-note/siyuan/kernel/util"
)
var validPackageTypes = map[string]bool{
"plugins": true,
"themes": true,
"icons": true,
"templates": true,
"widgets": true,
}
func batchUpdatePackage(c *gin.Context) {
ret := gulu.Ret.NewResult()
defer c.JSON(http.StatusOK, ret)
@ -34,7 +42,10 @@ func batchUpdatePackage(c *gin.Context) {
return
}
frontend := arg["frontend"].(string)
var frontend string
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("frontend", true, &frontend)) {
return
}
model.BatchUpdateBazaarPackages(frontend)
}
@ -47,7 +58,10 @@ func getUpdatedPackage(c *gin.Context) {
return
}
frontend := arg["frontend"].(string)
var frontend string
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("frontend", true, &frontend)) {
return
}
plugins, widgets, icons, themes, templates := model.UpdatedPackages(frontend)
ret.Data = map[string]interface{}{
"plugins": plugins,
@ -67,11 +81,21 @@ func getBazaarPackageREADME(c *gin.Context) {
return
}
repoURL := arg["repoURL"].(string)
repoHash := arg["repoHash"].(string)
packageType := arg["packageType"].(string)
var repoURL, repoHash, pkgType string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("repoURL", true, &repoURL),
util.BindJsonArg("repoHash", true, &repoHash),
util.BindJsonArg("packageType", true, &pkgType),
) {
return
}
if !validPackageTypes[pkgType] {
ret.Code = -1
ret.Msg = "Invalid package type"
return
}
ret.Data = map[string]interface{}{
"html": model.GetPackageREADME(repoURL, repoHash, packageType),
"html": model.GetPackageREADME(repoURL, repoHash, pkgType),
}
}
@ -84,10 +108,12 @@ func getBazaarPlugin(c *gin.Context) {
return
}
frontend := arg["frontend"].(string)
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var frontend, keyword string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("frontend", true, &frontend),
util.BindJsonArg("keyword", false, &keyword),
) {
return
}
ret.Data = map[string]interface{}{
@ -104,10 +130,12 @@ func getInstalledPlugin(c *gin.Context) {
return
}
frontend := arg["frontend"].(string)
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var frontend, keyword string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("frontend", true, &frontend),
util.BindJsonArg("keyword", false, &keyword),
) {
return
}
ret.Data = map[string]interface{}{
@ -124,14 +152,16 @@ func installBazaarPlugin(c *gin.Context) {
return
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var frontend, keyword, repoURL, repoHash, packageName string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("frontend", true, &frontend),
util.BindJsonArg("keyword", false, &keyword),
util.BindJsonArg("repoURL", true, &repoURL),
util.BindJsonArg("repoHash", true, &repoHash),
util.BindJsonArg("packageName", true, &packageName),
) {
return
}
repoURL := arg["repoURL"].(string)
repoHash := arg["repoHash"].(string)
packageName := arg["packageName"].(string)
err := model.InstallBazaarPlugin(repoURL, repoHash, packageName)
if err != nil {
ret.Code = 1
@ -139,8 +169,6 @@ func installBazaarPlugin(c *gin.Context) {
return
}
frontend := arg["frontend"].(string)
util.PushMsg(model.Conf.Language(69), 3000)
ret.Data = map[string]interface{}{
"packages": model.BazaarPlugins(frontend, keyword),
@ -156,13 +184,14 @@ func uninstallBazaarPlugin(c *gin.Context) {
return
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var frontend, keyword, packageName string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("frontend", true, &frontend),
util.BindJsonArg("keyword", false, &keyword),
util.BindJsonArg("packageName", true, &packageName),
) {
return
}
frontend := arg["frontend"].(string)
packageName := arg["packageName"].(string)
err := model.UninstallBazaarPlugin(packageName, frontend)
if err != nil {
ret.Code = -1
@ -185,8 +214,8 @@ func getBazaarWidget(c *gin.Context) {
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("keyword", false, &keyword)) {
return
}
ret.Data = map[string]interface{}{
@ -204,8 +233,8 @@ func getInstalledWidget(c *gin.Context) {
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("keyword", false, &keyword)) {
return
}
ret.Data = map[string]interface{}{
@ -222,14 +251,15 @@ func installBazaarWidget(c *gin.Context) {
return
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var keyword, repoURL, repoHash, packageName string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("keyword", false, &keyword),
util.BindJsonArg("repoURL", true, &repoURL),
util.BindJsonArg("repoHash", true, &repoHash),
util.BindJsonArg("packageName", true, &packageName),
) {
return
}
repoURL := arg["repoURL"].(string)
repoHash := arg["repoHash"].(string)
packageName := arg["packageName"].(string)
err := model.InstallBazaarWidget(repoURL, repoHash, packageName)
if err != nil {
ret.Code = 1
@ -252,12 +282,13 @@ func uninstallBazaarWidget(c *gin.Context) {
return
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var keyword, packageName string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("keyword", false, &keyword),
util.BindJsonArg("packageName", true, &packageName),
) {
return
}
packageName := arg["packageName"].(string)
err := model.UninstallBazaarWidget(packageName)
if err != nil {
ret.Code = -1
@ -280,8 +311,8 @@ func getBazaarIcon(c *gin.Context) {
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("keyword", false, &keyword)) {
return
}
ret.Data = map[string]interface{}{
@ -299,8 +330,8 @@ func getInstalledIcon(c *gin.Context) {
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("keyword", false, &keyword)) {
return
}
ret.Data = map[string]interface{}{
@ -317,14 +348,15 @@ func installBazaarIcon(c *gin.Context) {
return
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var keyword, repoURL, repoHash, packageName string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("keyword", false, &keyword),
util.BindJsonArg("repoURL", true, &repoURL),
util.BindJsonArg("repoHash", true, &repoHash),
util.BindJsonArg("packageName", true, &packageName),
) {
return
}
repoURL := arg["repoURL"].(string)
repoHash := arg["repoHash"].(string)
packageName := arg["packageName"].(string)
err := model.InstallBazaarIcon(repoURL, repoHash, packageName)
if err != nil {
ret.Code = 1
@ -348,12 +380,13 @@ func uninstallBazaarIcon(c *gin.Context) {
return
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var keyword, packageName string
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("keyword", false, &keyword),
util.BindJsonArg("packageName", true, &packageName),
) {
return
}
packageName := arg["packageName"].(string)
err := model.UninstallBazaarIcon(packageName)
if err != nil {
ret.Code = -1
@ -377,8 +410,8 @@ func getBazaarTemplate(c *gin.Context) {
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("keyword", false, &keyword)) {
return
}
ret.Data = map[string]interface{}{
@ -396,8 +429,8 @@ func getInstalledTemplate(c *gin.Context) {
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
if !util.ParseJsonArgs(arg, ret, util.BindJsonArg("keyword", false, &keyword)) {
return
}
ret.Data = map[string]interface{}{
@ -510,15 +543,17 @@ func installBazaarTheme(c *gin.Context) {
return
}
var keyword string
if keywordArg := arg["keyword"]; nil != keywordArg {
keyword = keywordArg.(string)
var keyword, repoURL, repoHash, packageName string
var mode float64
if !util.ParseJsonArgs(arg, ret,
util.BindJsonArg("keyword", false, &keyword),
util.BindJsonArg("repoURL", true, &repoURL),
util.BindJsonArg("repoHash", true, &repoHash),
util.BindJsonArg("packageName", true, &packageName),
util.BindJsonArg("mode", true, &mode),
) {
return
}
repoURL := arg["repoURL"].(string)
repoHash := arg["repoHash"].(string)
packageName := arg["packageName"].(string)
mode := arg["mode"].(float64)
update := false
if nil != arg["update"] {
update = arg["update"].(bool)
@ -530,6 +565,7 @@ func installBazaarTheme(c *gin.Context) {
return
}
// TODO 安装新主题之后,不应该始终取消外观模式“跟随系统” https://github.com/siyuan-note/siyuan/issues/16990
// 安装集市主题后不跟随系统切换外观模式
model.Conf.Appearance.ModeOS = false
model.Conf.Save()

View file

@ -17,6 +17,7 @@
package util
import (
"fmt"
"net"
"net/http"
"net/url"
@ -213,6 +214,58 @@ func JsonArg(c *gin.Context, result *gulu.Result) (arg map[string]interface{}, o
return
}
// ParseJsonArg 使用泛型从 JSON 参数中提取指定键的值。
// - 如果 required 为 true 但参数缺失,则会在 ret.Msg 中写入 “[key] is required”
// - 如果参数存在但类型不匹配,则会在 ret.Msg 中写入 “[key] should be [T]”
// - 返回值 ok 为 false 时,表示提取失败或类型不匹配
func ParseJsonArg[T any](key string, required bool, arg map[string]interface{}, ret *gulu.Result) (value T, ok bool) {
raw, exists := arg[key]
if !exists || raw == nil {
if required {
ret.Code = -1
ret.Msg = key + " is required"
} else {
ok = true
}
return
}
value, ok = raw.(T)
if !ok {
var zero T
ret.Code = -1
ret.Msg = fmt.Sprintf("%s should be %T", key, zero)
}
return
}
// JsonArgParseFunc 为单次提取函数,用于 ParseJsonArgs 批量提取。
type JsonArgParseFunc func(arg map[string]interface{}, ret *gulu.Result) bool
// BindJsonArg 创建一个提取函数:从 arg 取 key 并写入 dest供 ParseJsonArgs 使用。
func BindJsonArg[T any](key string, required bool, dest *T) JsonArgParseFunc {
return func(arg map[string]interface{}, ret *gulu.Result) bool {
v, ok := ParseJsonArg[T](key, required, arg, ret)
if !ok {
return false
}
*dest = v
return true
}
}
// ParseJsonArgs 按顺序执行多个提取函数。
// - 任一失败返回 false 并在 ret 中写入错误信息
// - 全部成功返回 true
func ParseJsonArgs(arg map[string]interface{}, ret *gulu.Result, extractors ...JsonArgParseFunc) bool {
for _, ext := range extractors {
if !ext(arg, ret) {
return false
}
}
return true
}
func InvalidIDPattern(idArg string, result *gulu.Result) bool {
if ast.IsNodeIDPattern(idArg) {
return false