From 33a996e7772d8f6e88ff3c49eac3d8fa8e0c1781 Mon Sep 17 00:00:00 2001 From: Jacky Date: Tue, 22 Oct 2024 16:38:38 +0800 Subject: [PATCH 01/13] refactor: migrate to new cosy --- .gitignore | 1 + api/analytic/analytic.go | 2 +- api/analytic/nodes.go | 2 +- api/api.go | 2 +- api/certificate/acme_user.go | 6 +- api/certificate/certificate.go | 2 +- api/certificate/dns_credential.go | 2 +- api/certificate/issue.go | 2 +- api/cluster/environment.go | 2 +- api/cluster/node.go | 2 +- api/config/list.go | 2 +- api/config/rename.go | 2 +- api/nginx/nginx_log.go | 2 +- api/notification/notification.go | 2 +- api/settings/settings.go | 17 +- api/sites/category.go | 41 +++ api/sites/domain.go | 63 +---- api/sites/list.go | 70 +++++ api/sites/router.go | 9 + api/system/install.go | 11 +- api/system/upgrade.go | 4 +- api/terminal/pty.go | 2 +- api/upstream/upstream.go | 2 +- api/user/auth.go | 2 +- api/user/otp.go | 4 +- api/user/passkey.go | 4 +- api/user/user.go | 4 +- app/src/components/StdDesign/types.d.ts | 1 - app/src/views/certificate/ACMEUser.vue | 10 +- .../CertificateList/certColumns.tsx | 8 +- app/src/views/certificate/DNSCredential.vue | 6 +- app/src/views/environment/envColumns.tsx | 12 +- .../notification/notificationColumns.tsx | 4 +- app/src/views/site/SiteList.vue | 6 +- app/src/views/stream/StreamList.vue | 6 +- app/src/views/user/userColumns.tsx | 10 +- go.mod | 20 +- go.sum | 267 +++++++++--------- img.png | Bin 0 -> 40441 bytes install.sh | 7 +- internal/analytic/analytic.go | 2 +- internal/analytic/node.go | 2 +- internal/analytic/node_record.go | 2 +- internal/analytic/node_stat.go | 2 +- internal/analytic/record.go | 2 +- internal/cache/cache.go | 2 +- internal/cert/auto_cert.go | 6 +- internal/cert/cert.go | 8 +- internal/cert/logger.go | 2 +- internal/cert/payload.go | 2 +- internal/cert/register.go | 18 +- internal/cert/sync.go | 2 +- internal/chatbot/context.go | 2 +- internal/cluster/cluster.go | 2 +- internal/config/sync.go | 4 +- internal/cosy/cosy.go | 117 -------- internal/cosy/create.go | 81 ------ internal/cosy/custom.go | 39 --- internal/cosy/delete.go | 113 -------- internal/cosy/error.go | 23 -- internal/cosy/filter.go | 212 -------------- internal/cosy/hook.go | 39 --- internal/cosy/list.go | 172 ----------- internal/cosy/map2struct/hook.go | 96 ------- internal/cosy/map2struct/map2struct.go | 25 -- internal/cosy/order.go | 46 --- internal/cosy/sort.go | 41 --- internal/cosy/update.go | 101 ------- internal/cron/cron.go | 2 +- internal/helper/directory.go | 2 +- internal/helper/hash.go | 2 +- internal/kernal/boot.go | 27 +- internal/kernal/register_acme_user.go | 2 +- internal/kernal/skip_install.go | 15 +- internal/logrotate/logrotate.go | 2 +- internal/middleware/middleware.go | 25 +- internal/middleware/proxy.go | 2 +- internal/middleware/proxy_ws.go | 2 +- internal/nginx/config_args.go | 2 +- internal/passkey/webauthn.go | 6 +- internal/pty/pipeline.go | 4 +- internal/template/template.go | 7 +- internal/transport/transport.go | 2 +- internal/upgrader/upgrade.go | 11 +- internal/user/user.go | 8 +- internal/validation/validation.go | 2 +- main.go | 38 +-- model/config_backup.go | 2 +- model/model.go | 42 +-- model/site_category.go | 7 + router/routers.go | 9 +- settings/app.testing.ini | 82 ++++++ settings/auth.go | 2 +- settings/casdoor.go | 2 +- settings/cert.go | 36 +++ settings/cluster.go | 8 +- settings/cluster_test.go | 16 -- settings/crypto.go | 2 +- settings/crypto_test.go | 6 +- settings/http.go | 11 + settings/logrotate.go | 2 +- settings/nginx.go | 2 +- settings/node.go | 15 + settings/openai.go | 2 +- settings/server.go | 63 ----- settings/server_v1.go | 227 +++++++++++++++ settings/server_v1_test.go | 125 ++++++++ settings/settings.go | 133 +++------ settings/settings_test.go | 189 +++++++++---- settings/terminal.go | 7 + settings/webauthn.go | 2 +- 111 files changed, 1164 insertions(+), 1773 deletions(-) create mode 100644 api/sites/category.go create mode 100644 api/sites/list.go create mode 100644 img.png delete mode 100644 internal/cosy/cosy.go delete mode 100644 internal/cosy/create.go delete mode 100644 internal/cosy/custom.go delete mode 100644 internal/cosy/delete.go delete mode 100644 internal/cosy/error.go delete mode 100644 internal/cosy/filter.go delete mode 100644 internal/cosy/hook.go delete mode 100644 internal/cosy/list.go delete mode 100644 internal/cosy/map2struct/hook.go delete mode 100644 internal/cosy/map2struct/map2struct.go delete mode 100644 internal/cosy/order.go delete mode 100644 internal/cosy/sort.go delete mode 100644 internal/cosy/update.go create mode 100644 model/site_category.go create mode 100644 settings/app.testing.ini create mode 100644 settings/cert.go delete mode 100644 settings/cluster_test.go create mode 100644 settings/http.go create mode 100644 settings/node.go delete mode 100644 settings/server.go create mode 100644 settings/server_v1.go create mode 100644 settings/server_v1_test.go create mode 100644 settings/terminal.go diff --git a/.gitignore b/.gitignore index 6ab491f9..095b6dbf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ tmp node_modules .pnpm-store app.ini +app.testing.ini dist *.exe *.po~ diff --git a/api/analytic/analytic.go b/api/analytic/analytic.go index 3551cf5c..918a3ee8 100644 --- a/api/analytic/analytic.go +++ b/api/analytic/analytic.go @@ -4,7 +4,7 @@ import ( "fmt" "github.com/0xJacky/Nginx-UI/internal/analytic" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/host" "github.com/shirou/gopsutil/v3/load" diff --git a/api/analytic/nodes.go b/api/analytic/nodes.go index b880991c..4f698c3b 100644 --- a/api/analytic/nodes.go +++ b/api/analytic/nodes.go @@ -3,7 +3,7 @@ package analytic import ( "github.com/0xJacky/Nginx-UI/internal/analytic" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "net/http" diff --git a/api/api.go b/api/api.go index e7237ddb..d5989690 100644 --- a/api/api.go +++ b/api/api.go @@ -2,7 +2,7 @@ package api import ( "errors" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/model" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" diff --git a/api/certificate/acme_user.go b/api/certificate/acme_user.go index 65928dc5..13431dd9 100644 --- a/api/certificate/acme_user.go +++ b/api/certificate/acme_user.go @@ -2,12 +2,12 @@ package certificate import ( "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/internal/cosy" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" "github.com/spf13/cast" + "github.com/uozi-tech/cosy" "net/http" ) @@ -31,7 +31,7 @@ func CreateAcmeUser(c *gin.Context) { "register_on_startup": "omitempty", }).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AcmeUser]) { if ctx.Model.CADir == "" { - ctx.Model.CADir = settings.ServerSettings.GetCADir() + ctx.Model.CADir = settings.CertSettings.GetCADir() } err := ctx.Model.Register() if err != nil { @@ -50,7 +50,7 @@ func ModifyAcmeUser(c *gin.Context) { "register_on_startup": "omitempty", }).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AcmeUser]) { if ctx.Model.CADir == "" { - ctx.Model.CADir = settings.ServerSettings.GetCADir() + ctx.Model.CADir = settings.CertSettings.GetCADir() } if ctx.OriginModel.Email != ctx.Model.Email || diff --git a/api/certificate/certificate.go b/api/certificate/certificate.go index a2dd0c68..f333cfc9 100644 --- a/api/certificate/certificate.go +++ b/api/certificate/certificate.go @@ -3,7 +3,6 @@ package certificate import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/cert" - "github.com/0xJacky/Nginx-UI/internal/cosy" "github.com/0xJacky/Nginx-UI/internal/helper" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/internal/notification" @@ -12,6 +11,7 @@ import ( "github.com/gin-gonic/gin" "github.com/go-acme/lego/v4/certcrypto" "github.com/spf13/cast" + "github.com/uozi-tech/cosy" "net/http" "os" ) diff --git a/api/certificate/dns_credential.go b/api/certificate/dns_credential.go index 59df26d8..0fec35f4 100644 --- a/api/certificate/dns_credential.go +++ b/api/certificate/dns_credential.go @@ -3,11 +3,11 @@ package certificate import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/cert/dns" - "github.com/0xJacky/Nginx-UI/internal/cosy" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/gin-gonic/gin" "github.com/spf13/cast" + "github.com/uozi-tech/cosy" "net/http" ) diff --git a/api/certificate/issue.go b/api/certificate/issue.go index f5a7e78d..bd9b70e7 100644 --- a/api/certificate/issue.go +++ b/api/certificate/issue.go @@ -2,7 +2,7 @@ package certificate import ( "github.com/0xJacky/Nginx-UI/internal/cert" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/model" "github.com/gin-gonic/gin" "github.com/go-acme/lego/v4/certcrypto" diff --git a/api/cluster/environment.go b/api/cluster/environment.go index fb0686cb..ca9f5310 100644 --- a/api/cluster/environment.go +++ b/api/cluster/environment.go @@ -4,12 +4,12 @@ import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/analytic" "github.com/0xJacky/Nginx-UI/internal/cluster" - "github.com/0xJacky/Nginx-UI/internal/cosy" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" "github.com/spf13/cast" + "github.com/uozi-tech/cosy" "gorm.io/gorm" "net/http" ) diff --git a/api/cluster/node.go b/api/cluster/node.go index 57848efb..75c54f32 100644 --- a/api/cluster/node.go +++ b/api/cluster/node.go @@ -12,7 +12,7 @@ import ( ) func GetCurrentNode(c *gin.Context) { - if _, ok := c.Get("NodeSecret"); !ok { + if _, ok := c.Get("Secret"); !ok { c.JSON(http.StatusNotAcceptable, gin.H{ "message": "node secret not exist", }) diff --git a/api/config/list.go b/api/config/list.go index 44b31aa4..27e517d7 100644 --- a/api/config/list.go +++ b/api/config/list.go @@ -3,7 +3,7 @@ package config import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/config" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/gin-gonic/gin" "net/http" diff --git a/api/config/rename.go b/api/config/rename.go index f028833f..e90542a6 100644 --- a/api/config/rename.go +++ b/api/config/rename.go @@ -4,7 +4,7 @@ import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/config" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/query" "github.com/gin-gonic/gin" diff --git a/api/nginx/nginx_log.go b/api/nginx/nginx_log.go index 2ac82319..22661ded 100644 --- a/api/nginx/nginx_log.go +++ b/api/nginx/nginx_log.go @@ -6,7 +6,7 @@ import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/cache" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" diff --git a/api/notification/notification.go b/api/notification/notification.go index 1a3998d2..f0c02304 100644 --- a/api/notification/notification.go +++ b/api/notification/notification.go @@ -2,11 +2,11 @@ package notification import ( "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/internal/cosy" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/gin-gonic/gin" "github.com/spf13/cast" + "github.com/uozi-tech/cosy" "net/http" ) diff --git a/api/settings/settings.go b/api/settings/settings.go index 1c6ad46d..c0bab080 100644 --- a/api/settings/settings.go +++ b/api/settings/settings.go @@ -6,12 +6,13 @@ import ( "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" + cSettings "github.com/uozi-tech/cosy/settings" "net/http" ) func GetServerName(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ - "name": settings.ServerSettings.Name, + "name": settings.NodeSettings.Name, }) } @@ -19,7 +20,7 @@ func GetSettings(c *gin.Context) { settings.NginxSettings.AccessLogPath = nginx.GetAccessLogPath() settings.NginxSettings.ErrorLogPath = nginx.GetErrorLogPath() c.JSON(http.StatusOK, gin.H{ - "server": settings.ServerSettings, + "server": cSettings.ServerSettings, "nginx": settings.NginxSettings, "openai": settings.OpenAISettings, "logrotate": settings.LogrotateSettings, @@ -29,7 +30,7 @@ func GetSettings(c *gin.Context) { func SaveSettings(c *gin.Context) { var json struct { - Server settings.Server `json:"server"` + Server cSettings.Server `json:"server"` Nginx settings.Nginx `json:"nginx"` Openai settings.OpenAI `json:"openai"` Logrotate settings.Logrotate `json:"logrotate"` @@ -45,11 +46,11 @@ func SaveSettings(c *gin.Context) { go cron.RestartLogrotate() } - settings.ProtectedFill(&settings.ServerSettings, &json.Server) - settings.ProtectedFill(&settings.NginxSettings, &json.Nginx) - settings.ProtectedFill(&settings.OpenAISettings, &json.Openai) - settings.ProtectedFill(&settings.LogrotateSettings, &json.Logrotate) - settings.ProtectedFill(&settings.AuthSettings, &json.Auth) + cSettings.ProtectedFill(cSettings.ServerSettings, &json.Server) + cSettings.ProtectedFill(settings.NginxSettings, &json.Nginx) + cSettings.ProtectedFill(settings.OpenAISettings, &json.Openai) + cSettings.ProtectedFill(settings.LogrotateSettings, &json.Logrotate) + cSettings.ProtectedFill(settings.AuthSettings, &json.Auth) err := settings.Save() if err != nil { diff --git a/api/sites/category.go b/api/sites/category.go new file mode 100644 index 00000000..d8ded05d --- /dev/null +++ b/api/sites/category.go @@ -0,0 +1,41 @@ +package sites + +import ( + "github.com/0xJacky/Nginx-UI/model" + "github.com/gin-gonic/gin" + "github.com/uozi-tech/cosy" +) + +func GetCategory(c *gin.Context) { + +} + +func GetCategoryList(c *gin.Context) { + cosy.Core[model.SiteCategory](c).PagingList() +} + +func AddCategory(c *gin.Context) { + cosy.Core[model.SiteCategory](c). + SetValidRules(gin.H{ + "name": "required", + "sync_node_ids": "omitempty", + }). + Create() +} + +func ModifyCategory(c *gin.Context) { + cosy.Core[model.SiteCategory](c). + SetValidRules(gin.H{ + "name": "required", + "sync_node_ids": "omitempty", + }). + Modify() +} + +func DeleteCategory(c *gin.Context) { + cosy.Core[model.SiteCategory](c).Destroy() +} + +func RecoverCategory(c *gin.Context) { + cosy.Core[model.SiteCategory](c).Recover() +} diff --git a/api/sites/domain.go b/api/sites/domain.go index 00b8c295..8956ffc6 100644 --- a/api/sites/domain.go +++ b/api/sites/domain.go @@ -3,9 +3,8 @@ package sites import ( "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/cert" - "github.com/0xJacky/Nginx-UI/internal/config" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" @@ -13,68 +12,8 @@ import ( "github.com/sashabaranov/go-openai" "net/http" "os" - "strings" ) -func GetSiteList(c *gin.Context) { - name := c.Query("name") - enabled := c.Query("enabled") - orderBy := c.Query("order_by") - sort := c.DefaultQuery("sort", "desc") - - configFiles, err := os.ReadDir(nginx.GetConfPath("sites-available")) - if err != nil { - api.ErrHandler(c, err) - return - } - - enabledConfig, err := os.ReadDir(nginx.GetConfPath("sites-enabled")) - if err != nil { - api.ErrHandler(c, err) - return - } - - enabledConfigMap := make(map[string]bool) - for i := range enabledConfig { - enabledConfigMap[enabledConfig[i].Name()] = true - } - - var configs []config.Config - - for i := range configFiles { - file := configFiles[i] - fileInfo, _ := file.Info() - if !file.IsDir() { - // name filter - if name != "" && !strings.Contains(file.Name(), name) { - continue - } - // status filter - if enabled != "" { - if enabled == "true" && !enabledConfigMap[file.Name()] { - continue - } - if enabled == "false" && enabledConfigMap[file.Name()] { - continue - } - } - configs = append(configs, config.Config{ - Name: file.Name(), - ModifiedAt: fileInfo.ModTime(), - Size: fileInfo.Size(), - IsDir: fileInfo.IsDir(), - Enabled: enabledConfigMap[file.Name()], - }) - } - } - - configs = config.Sort(orderBy, sort, configs) - - c.JSON(http.StatusOK, gin.H{ - "data": configs, - }) -} - func GetSite(c *gin.Context) { rewriteName, ok := c.Get("rewriteConfigFileName") name := c.Param("name") diff --git a/api/sites/list.go b/api/sites/list.go new file mode 100644 index 00000000..1cb29c93 --- /dev/null +++ b/api/sites/list.go @@ -0,0 +1,70 @@ +package sites + +import ( + "github.com/0xJacky/Nginx-UI/api" + "github.com/0xJacky/Nginx-UI/internal/config" + "github.com/0xJacky/Nginx-UI/internal/nginx" + "github.com/gin-gonic/gin" + "net/http" + "os" + "strings" +) + +func GetSiteList(c *gin.Context) { + name := c.Query("name") + enabled := c.Query("enabled") + orderBy := c.Query("order_by") + sort := c.DefaultQuery("sort", "desc") + + configFiles, err := os.ReadDir(nginx.GetConfPath("sites-available")) + if err != nil { + api.ErrHandler(c, err) + return + } + + enabledConfig, err := os.ReadDir(nginx.GetConfPath("sites-enabled")) + if err != nil { + api.ErrHandler(c, err) + return + } + + enabledConfigMap := make(map[string]bool) + for i := range enabledConfig { + enabledConfigMap[enabledConfig[i].Name()] = true + } + + var configs []config.Config + + for i := range configFiles { + file := configFiles[i] + fileInfo, _ := file.Info() + if !file.IsDir() { + // name filter + if name != "" && !strings.Contains(file.Name(), name) { + continue + } + // status filter + if enabled != "" { + if enabled == "true" && !enabledConfigMap[file.Name()] { + continue + } + if enabled == "false" && enabledConfigMap[file.Name()] { + continue + } + } + configs = append(configs, config.Config{ + Name: file.Name(), + ModifiedAt: fileInfo.ModTime(), + Size: fileInfo.Size(), + IsDir: fileInfo.IsDir(), + Enabled: enabledConfigMap[file.Name()], + }) + } + } + + configs = config.Sort(orderBy, sort, configs) + + c.JSON(http.StatusOK, gin.H{ + "data": configs, + }) +} diff --git a/api/sites/router.go b/api/sites/router.go index 2a2f3381..a604e77c 100644 --- a/api/sites/router.go +++ b/api/sites/router.go @@ -14,3 +14,12 @@ func InitRouter(r *gin.RouterGroup) { r.POST("auto_cert/:name", AddDomainToAutoCert) r.DELETE("auto_cert/:name", RemoveDomainFromAutoCert) } + +func InitCategoryRouter(r *gin.RouterGroup) { + r.GET("site_categories", GetCategoryList) + r.GET("site_category/:id", GetCategory) + r.POST("site_category", AddCategory) + r.PUT("site_category/:id", ModifyCategory) + r.DELETE("site_category/:id", DeleteCategory) + r.POST("site_category/:id/recover", RecoverCategory) +} diff --git a/api/system/install.go b/api/system/install.go index 94fc52c7..1d86c101 100644 --- a/api/system/install.go +++ b/api/system/install.go @@ -8,12 +8,13 @@ import ( "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" "github.com/google/uuid" + cSettings "github.com/uozi-tech/cosy/settings" "golang.org/x/crypto/bcrypt" "net/http" ) func installLockStatus() bool { - return settings.ServerSettings.SkipInstallation || "" != settings.ServerSettings.JwtSecret + return settings.NodeSettings.SkipInstallation || "" != cSettings.AppSettings.JwtSecret } func InstallLockCheck(c *gin.Context) { @@ -43,11 +44,11 @@ func InstallNginxUI(c *gin.Context) { return } - settings.ServerSettings.JwtSecret = uuid.New().String() - settings.ServerSettings.NodeSecret = uuid.New().String() - settings.ServerSettings.Email = json.Email + cSettings.AppSettings.JwtSecret = uuid.New().String() + settings.NodeSettings.Secret = uuid.New().String() + settings.CertSettings.Email = json.Email if "" != json.Database { - settings.ServerSettings.Database = json.Database + cSettings.DataBaseSettings.Name = json.Database } err := settings.Save() diff --git a/api/system/upgrade.go b/api/system/upgrade.go index 1b245e69..3dbd3478 100644 --- a/api/system/upgrade.go +++ b/api/system/upgrade.go @@ -2,11 +2,11 @@ package system import ( "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/upgrader" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" + "github.com/uozi-tech/cosy/logger" "net/http" "os" ) @@ -135,7 +135,7 @@ func PerformCoreUpgrade(c *gin.Context) { Message: "Performing core upgrade", }) // dry run - if control.DryRun || settings.ServerSettings.Demo { + if control.DryRun || settings.NodeSettings.Demo { return } diff --git a/api/terminal/pty.go b/api/terminal/pty.go index c8cde40b..c7abf154 100644 --- a/api/terminal/pty.go +++ b/api/terminal/pty.go @@ -1,7 +1,7 @@ package terminal import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/pty" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" diff --git a/api/upstream/upstream.go b/api/upstream/upstream.go index 0839b10b..64a6ee86 100644 --- a/api/upstream/upstream.go +++ b/api/upstream/upstream.go @@ -2,7 +2,7 @@ package upstream import ( "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/upstream" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" diff --git a/api/user/auth.go b/api/user/auth.go index 28d618cd..d3565ceb 100644 --- a/api/user/auth.go +++ b/api/user/auth.go @@ -2,7 +2,7 @@ package user import ( "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/user" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" diff --git a/api/user/otp.go b/api/user/otp.go index 26ee3356..368c211c 100644 --- a/api/user/otp.go +++ b/api/user/otp.go @@ -21,7 +21,7 @@ import ( func GenerateTOTP(c *gin.Context) { u := api.CurrentUser(c) - issuer := fmt.Sprintf("Nginx UI %s", settings.ServerSettings.Name) + issuer := fmt.Sprintf("Nginx UI %s", settings.NodeSettings.Name) issuer = strings.TrimSpace(issuer) otpOpts := totp.GenerateOpts{ @@ -70,7 +70,7 @@ func EnrollTOTP(c *gin.Context) { return } - if settings.ServerSettings.Demo { + if settings.NodeSettings.Demo { c.JSON(http.StatusBadRequest, gin.H{ "message": "This feature is disabled in demo mode", }) diff --git a/api/user/passkey.go b/api/user/passkey.go index a79174db..c27260e3 100644 --- a/api/user/passkey.go +++ b/api/user/passkey.go @@ -5,8 +5,6 @@ import ( "fmt" "github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/internal/cache" - "github.com/0xJacky/Nginx-UI/internal/cosy" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/passkey" "github.com/0xJacky/Nginx-UI/internal/user" "github.com/0xJacky/Nginx-UI/model" @@ -15,6 +13,8 @@ import ( "github.com/go-webauthn/webauthn/webauthn" "github.com/google/uuid" "github.com/spf13/cast" + "github.com/uozi-tech/cosy" + "github.com/uozi-tech/cosy/logger" "gorm.io/gorm" "net/http" "strings" diff --git a/api/user/user.go b/api/user/user.go index 4080dce5..bfbe9ecc 100644 --- a/api/user/user.go +++ b/api/user/user.go @@ -2,12 +2,12 @@ package user import ( "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/internal/cosy" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" "github.com/spf13/cast" + "github.com/uozi-tech/cosy" "golang.org/x/crypto/bcrypt" "net/http" ) @@ -71,7 +71,7 @@ func AddUser(c *gin.Context) { func EditUser(c *gin.Context) { userId := cast.ToInt(c.Param("id")) - if settings.ServerSettings.Demo && userId == 1 { + if settings.NodeSettings.Demo && userId == 1 { c.JSON(http.StatusNotAcceptable, gin.H{ "message": "Changing user password is forbidden in demo mode", }) diff --git a/app/src/components/StdDesign/types.d.ts b/app/src/components/StdDesign/types.d.ts index 05bc76bd..c8053e43 100644 --- a/app/src/components/StdDesign/types.d.ts +++ b/app/src/components/StdDesign/types.d.ts @@ -77,7 +77,6 @@ export interface Column extends TableColumnType { extra?: string | (() => string) pithy?: boolean search?: boolean | StdDesignEdit - sortable?: boolean handle?: boolean hiddenInTable?: boolean hiddenInTrash?: boolean diff --git a/app/src/views/certificate/ACMEUser.vue b/app/src/views/certificate/ACMEUser.vue index 7c88efcc..3d7a38ca 100644 --- a/app/src/views/certificate/ACMEUser.vue +++ b/app/src/views/certificate/ACMEUser.vue @@ -12,7 +12,7 @@ const columns: Column[] = [ { title: () => $gettext('Name'), dataIndex: 'name', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -23,7 +23,7 @@ const columns: Column[] = [ }, { title: () => $gettext('Email'), dataIndex: 'email', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -34,7 +34,7 @@ const columns: Column[] = [ }, { title: () => $gettext('CA Dir'), dataIndex: 'ca_dir', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -66,7 +66,7 @@ const columns: Column[] = [ return {$gettext('Invalid')} }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Register On Startup'), @@ -82,7 +82,7 @@ const columns: Column[] = [ title: () => $gettext('Updated at'), dataIndex: 'updated_at', customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Action'), diff --git a/app/src/views/certificate/CertificateList/certColumns.tsx b/app/src/views/certificate/CertificateList/certColumns.tsx index 8211c5f5..289e10b4 100644 --- a/app/src/views/certificate/CertificateList/certColumns.tsx +++ b/app/src/views/certificate/CertificateList/certColumns.tsx @@ -9,7 +9,7 @@ import { PrivateKeyTypeMask } from '@/constants' const columns: Column[] = [{ title: () => $gettext('Name'), dataIndex: 'name', - sortable: true, + sorter: true, pithy: true, customRender: (args: customRender) => { const { text, record } = args @@ -48,13 +48,13 @@ const columns: Column[] = [{ return h('div', template) }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Key Type'), dataIndex: 'key_type', customRender: mask(PrivateKeyTypeMask), - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Status'), @@ -83,7 +83,7 @@ const columns: Column[] = [{ title: () => $gettext('Not After'), dataIndex: ['certificate_info', 'not_after'], customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Action'), diff --git a/app/src/views/certificate/DNSCredential.vue b/app/src/views/certificate/DNSCredential.vue index 10c7d41d..d9d080cf 100644 --- a/app/src/views/certificate/DNSCredential.vue +++ b/app/src/views/certificate/DNSCredential.vue @@ -10,7 +10,7 @@ import type { Column } from '@/components/StdDesign/types' const columns: Column[] = [{ title: () => $gettext('Name'), dataIndex: 'name', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -21,13 +21,13 @@ const columns: Column[] = [{ customRender: (args: customRender) => { return args.record.provider }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Updated at'), dataIndex: 'updated_at', customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Action'), diff --git a/app/src/views/environment/envColumns.tsx b/app/src/views/environment/envColumns.tsx index da594971..58f7af57 100644 --- a/app/src/views/environment/envColumns.tsx +++ b/app/src/views/environment/envColumns.tsx @@ -8,7 +8,7 @@ import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransfor const columns: Column[] = [{ title: () => $gettext('Name'), dataIndex: 'name', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -18,7 +18,7 @@ const columns: Column[] = [{ { title: () => $gettext('URL'), dataIndex: 'url', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -35,7 +35,7 @@ const columns: Column[] = [{ { title: () => 'NodeSecret', dataIndex: 'token', - sortable: true, + sorter: true, hiddenInTable: true, edit: { type: input, @@ -97,7 +97,7 @@ const columns: Column[] = [{ return h('div', template) }, - sortable: true, + sorter: true, pithy: true, }, { @@ -117,14 +117,14 @@ const columns: Column[] = [{ edit: { type: switcher, }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Updated at'), dataIndex: 'updated_at', customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { diff --git a/app/src/views/notification/notificationColumns.tsx b/app/src/views/notification/notificationColumns.tsx index 3be96594..5a997994 100644 --- a/app/src/views/notification/notificationColumns.tsx +++ b/app/src/views/notification/notificationColumns.tsx @@ -30,7 +30,7 @@ const columns: Column[] = [{ } }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Title'), @@ -47,7 +47,7 @@ const columns: Column[] = [{ }, { title: () => $gettext('Created at'), dataIndex: 'created_at', - sortable: true, + sorter: true, customRender: datetime, pithy: true, }, { diff --git a/app/src/views/site/SiteList.vue b/app/src/views/site/SiteList.vue index 9a5a24db..40a863f8 100644 --- a/app/src/views/site/SiteList.vue +++ b/app/src/views/site/SiteList.vue @@ -12,7 +12,7 @@ import type { Column, JSXElements } from '@/components/StdDesign/types' const columns: Column[] = [{ title: () => $gettext('Name'), dataIndex: 'name', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -42,13 +42,13 @@ const columns: Column[] = [{ false: $gettext('Disabled'), }, }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Updated at'), dataIndex: 'modified_at', customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Action'), diff --git a/app/src/views/stream/StreamList.vue b/app/src/views/stream/StreamList.vue index f751e7c1..244c65aa 100644 --- a/app/src/views/stream/StreamList.vue +++ b/app/src/views/stream/StreamList.vue @@ -12,7 +12,7 @@ import StreamDuplicate from '@/views/stream/components/StreamDuplicate.vue' const columns: Column[] = [{ title: () => $gettext('Name'), dataIndex: 'name', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -35,13 +35,13 @@ const columns: Column[] = [{ return h('div', template) }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Updated at'), dataIndex: 'modified_at', customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Action'), diff --git a/app/src/views/user/userColumns.tsx b/app/src/views/user/userColumns.tsx index 67b6e1f5..24eac21f 100644 --- a/app/src/views/user/userColumns.tsx +++ b/app/src/views/user/userColumns.tsx @@ -8,7 +8,7 @@ import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransfor const columns: Column[] = [{ title: () => $gettext('Username'), dataIndex: 'name', - sortable: true, + sorter: true, pithy: true, edit: { type: input, @@ -17,7 +17,7 @@ const columns: Column[] = [{ }, { title: () => $gettext('Password'), dataIndex: 'password', - sortable: true, + sorter: true, pithy: true, edit: { type: password, @@ -42,19 +42,19 @@ const columns: Column[] = [{ return h('div', template) }, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Created at'), dataIndex: 'created_at', customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Updated at'), dataIndex: 'updated_at', customRender: datetime, - sortable: true, + sorter: true, pithy: true, }, { title: () => $gettext('Action'), diff --git a/go.mod b/go.mod index 4d600b92..4ac64e22 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/creack/pty v1.1.23 github.com/dgraph-io/ristretto v1.0.0 github.com/dustin/go-humanize v1.0.1 + github.com/elliotchance/orderedmap/v2 v2.4.0 github.com/fatih/color v1.17.0 github.com/gin-contrib/static v1.1.2 github.com/gin-gonic/gin v1.10.0 @@ -24,20 +25,19 @@ require ( github.com/jpillora/overseer v1.1.6 github.com/lib/pq v1.10.9 github.com/minio/selfupdate v0.6.0 - github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.4.0 github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308 github.com/samber/lo v1.47.0 github.com/sashabaranov/go-openai v1.32.2 github.com/shirou/gopsutil/v3 v3.24.5 - github.com/shopspring/decimal v1.4.0 github.com/spf13/cast v1.7.0 github.com/stretchr/testify v1.9.0 github.com/tufanbarisyildirim/gonginx v0.0.0-20241013191809-e73b7dd454e8 + github.com/uozi-tech/cosy v1.9.4 + github.com/uozi-tech/cosy-driver-sqlite v0.2.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.28.0 - gopkg.in/guregu/null.v4 v4.0.0 gopkg.in/ini.v1 v1.67.0 gorm.io/driver/sqlite v1.5.6 gorm.io/gen v0.3.26 @@ -90,8 +90,9 @@ require ( github.com/aws/smithy-go v1.22.0 // indirect github.com/benbjohnson/clock v1.3.5 // indirect github.com/boombuler/barcode v1.0.2 // indirect + github.com/bsm/redislock v0.9.4 // indirect github.com/bytedance/sonic v1.12.3 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/civo/civogo v0.3.84 // indirect @@ -100,6 +101,7 @@ require ( github.com/cloudwego/iasm v0.2.0 // indirect github.com/cpu/goacmedns v0.1.1 // 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/dimchansky/utfbom v1.1.1 // indirect github.com/dnsimple/dnsimple-go v1.7.0 // indirect github.com/exoscale/egoscale/v3 v3.1.7 // indirect @@ -110,6 +112,7 @@ require ( github.com/gabriel-vasile/mimetype v1.4.6 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-co-op/gocron/v2 v2.12.1 // indirect github.com/go-errors/errors v1.5.1 // indirect github.com/go-jose/go-jose/v4 v4.0.4 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -144,9 +147,12 @@ require ( github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect github.com/itchyny/timefmt-go v0.1.6 // indirect + github.com/jackc/pgio v1.0.0 // indirect + github.com/jackc/pgtype v1.14.4 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect github.com/jpillora/s3 v1.1.4 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect @@ -167,6 +173,7 @@ require ( github.com/miekg/dns v1.1.62 // indirect github.com/mimuret/golang-iij-dpf v0.9.1 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect @@ -190,6 +197,7 @@ require ( github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect + github.com/redis/go-redis/v9 v9.7.0 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sacloud/api-client-go v0.2.10 // indirect github.com/sacloud/go-http v0.1.8 // indirect @@ -201,11 +209,13 @@ require ( github.com/selectel/domains-go v1.1.0 // indirect github.com/selectel/go-selvpcclient/v3 v3.1.1 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect github.com/softlayer/softlayer-go v1.1.6 // indirect github.com/softlayer/xmlrpc v0.0.0-20200409220501-5f089df7cb7e // indirect github.com/sony/gobreaker v1.0.0 // indirect + github.com/sony/sonyflake v1.2.0 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -252,6 +262,7 @@ require ( google.golang.org/grpc v1.67.1 // indirect google.golang.org/protobuf v1.35.1 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/guregu/null.v4 v4.0.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ns1/ns1-go.v2 v2.12.2 // indirect gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect @@ -259,7 +270,6 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/datatypes v1.2.4 // indirect gorm.io/driver/mysql v1.5.7 // indirect - gorm.io/driver/postgres v1.5.6 // indirect gorm.io/hints v1.1.2 // indirect k8s.io/api v0.31.1 // indirect k8s.io/apimachinery v0.31.1 // indirect diff --git a/go.sum b/go.sum index ee6b8a30..9a17ffe0 100644 --- a/go.sum +++ b/go.sum @@ -39,8 +39,6 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -102,8 +100,6 @@ cloud.google.com/go/assuredworkloads v1.7.0/go.mod h1:z/736/oNmtGAyU47reJgGN+KVo cloud.google.com/go/assuredworkloads v1.8.0/go.mod h1:AsX2cqyNCOvEQC8RMPnoc0yEarXQk6WEKkxYfL6kGIo= cloud.google.com/go/assuredworkloads v1.9.0/go.mod h1:kFuI1P78bplYtT77Tb1hi0FMxM0vVpRC7VVoJC3ZoT0= cloud.google.com/go/assuredworkloads v1.10.0/go.mod h1:kwdUQuXcedVdsIaKgKTp9t0UJkE5+PAVNhdQm4ZVq2E= -cloud.google.com/go/auth v0.9.7 h1:ha65jNwOfI48YmUzNfMaUDfqt5ykuYIUnSartpU1+BA= -cloud.google.com/go/auth v0.9.7/go.mod h1:Xo0n7n66eHyOWWCnitop6870Ilwo3PiZyodVkkH1xWM= cloud.google.com/go/auth v0.9.8 h1:+CSJ0Gw9iVeSENVCKJoLHhdUykDgXSc4Qn+gu2BRtR8= cloud.google.com/go/auth v0.9.8/go.mod h1:xxA5AqpDrvS+Gkmo9RqrGGRh6WSNKKOXhY3zNOr38tI= cloud.google.com/go/auth/oauth2adapt v0.2.4 h1:0GWE/FUsXhf6C+jAkWgYm7X9tK8cuEIfy19DBn6B6bY= @@ -182,7 +178,6 @@ cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvj cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= -cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -617,16 +612,12 @@ github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 h1:Dy3M9aegiI7d7PF1LUdjbVigJReo+QOceYs github.com/AdamSLevy/jsonrpc2/v14 v14.1.0/go.mod h1:ZakZtbCXxCz82NJvq7MoREtiQesnDfrtF6RFUGzQfLo= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.15.0 h1:eXzkOEXbSTOa7cJ7EqeCVi/OFi/ppDrUtQuttCWy74c= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.15.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c= @@ -663,6 +654,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -672,6 +665,7 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo= github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24= github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks= @@ -689,10 +683,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.23 h1:qVHm1EZhZ4JGfB9RMHREtbcNcPDDFyCKA+0/nMk6JP8= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.23/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.28 h1:sfIgg5sLKlJQJonmnY43YHCU3mvTOyFSQgE3FNCl63U= -github.com/aliyun/alibaba-cloud-sdk-go v1.63.28/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/aliyun/alibaba-cloud-sdk-go v1.63.32 h1:aBtZr6N7HXVpJCMybTSBuinHauehf/R0LNMB03TkrE0= github.com/aliyun/alibaba-cloud-sdk-go v1.63.32/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= @@ -705,58 +695,32 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV github.com/armon/go-metrics v0.4.0/go.mod h1:E6amYzXo6aW1tqzoZGT755KkbgrJsSdpwZ+3JqfkOG4= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.32.0 h1:GuHp7GvMN74PXD5C97KT5D87UhIy4bQPkflQKbfkndg= -github.com/aws/aws-sdk-go-v2 v1.32.0/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= github.com/aws/aws-sdk-go-v2 v1.32.2 h1:AkNLZEyYMLnx/Q/mSKkcMqwNFXMAvFto9bNsHqcTduI= github.com/aws/aws-sdk-go-v2 v1.32.2/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= -github.com/aws/aws-sdk-go-v2/config v1.27.41 h1:esG3WpmEuNJ6F4kVFLumN8nCfA5VBav1KKb3JPx83O4= -github.com/aws/aws-sdk-go-v2/config v1.27.41/go.mod h1:haUg09ebP+ClvPjU3EB/xe0HF9PguO19PD2fdjM2X14= -github.com/aws/aws-sdk-go-v2/config v1.27.43 h1:p33fDDihFC390dhhuv8nOmX419wjOSDQRb+USt20RrU= -github.com/aws/aws-sdk-go-v2/config v1.27.43/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= github.com/aws/aws-sdk-go-v2/config v1.28.0 h1:FosVYWcqEtWNxHn8gB/Vs6jOlNwSoyOCA/g/sxyySOQ= github.com/aws/aws-sdk-go-v2/config v1.28.0/go.mod h1:pYhbtvg1siOOg8h5an77rXle9tVG8T+BWLWAo7cOukc= -github.com/aws/aws-sdk-go-v2/credentials v1.17.39 h1:tmVexAhoGqJxNE2oc4/SJqL+Jz1x1iCPt5ts9XcqZCU= -github.com/aws/aws-sdk-go-v2/credentials v1.17.39/go.mod h1:zgOdbDI9epE608PdboJ87CYvPIejAgFevazeJW6iauQ= github.com/aws/aws-sdk-go-v2/credentials v1.17.41 h1:7gXo+Axmp+R4Z+AK8YFQO0ZV3L0gizGINCOWxSLY9W8= github.com/aws/aws-sdk-go-v2/credentials v1.17.41/go.mod h1:u4Eb8d3394YLubphT4jLEwN1rLNq2wFOlT6OuxFwPzU= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.15 h1:kGjlNc2IXXcxPDcfMyCshNCjVgxUhC/vTJv7NvC9wKk= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.15/go.mod h1:rk/HmqPo+dX0Uv0Q1+4w3QKFdICEGSsTYz1hRWvH8UI= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17 h1:TMH3f/SCAWdNtXXVPPu5D6wrr4G5hI1rAxbcocKfC7Q= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.17/go.mod h1:1ZRXLdTpzdJb9fwTMXiLipENRxkGMTn1sfKexGllQCw= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.19 h1:Q/k5wCeJkSWs+62kDfOillkNIJ5NqmE3iOfm48g/W8c= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.19/go.mod h1:Wns1C66VvtA2Bv/cUBuKZKQKdjo7EVMhp90aAa+8oTI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21 h1:UAsR3xA31QGf79WzpG/ixT9FZvQlh5HY1NRqSHBNOCk= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.21/go.mod h1:JNr43NFf5L9YaG3eKTm7HQzls9J+A9YYcGI5Quh1r2Y= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.19 h1:AYLE0lUfKvN6icFTR/p+NmD1amYKTbqHQ1Nm+jwE6BM= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.19/go.mod h1:1giLakj64GjuH1NBzF/DXqly5DWHtMTaOzRZ53nFX0I= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21 h1:6jZVETqmYCadGFvrYEQfC5fAQmlo80CeL5psbno6r0s= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.21/go.mod h1:1SR0GbLlnN3QUmYaflZNiH1ql+1qrSiB2vwcJ+4UM60= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.0 h1:AdbiDUgQZmM28rDIZbiSwFxz8+3B94aOXxzs6oH+EA0= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.0/go.mod h1:uV476Bd80tiDTX4X2redMtagQUg65aU/gzPojSJ4kSI= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.0 h1:vUdg9qrgYd8ShPj8FhE3qfBx+UoOH2ZJW1Te/V4Hn+I= -github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.0/go.mod h1:TWMPrc4+ZJRzkrDBUNOQzhVqhhUqv7DRkgoboTn4PGk= github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.2 h1:KACHg9TlCAph5Brs8RqVrm1SK0FVLBiDPhkZApIG5x4= github.com/aws/aws-sdk-go-v2/service/lightsail v1.42.2/go.mod h1:eZZLyXEbSmrhlNXeGnZUyBUQXUwnzaJqT8tFoQGxSRA= -github.com/aws/aws-sdk-go-v2/service/route53 v1.45.0 h1:rwDRzOudNWFLRmpHIC6zZjGKovvgdfobPgXn/aXTdcs= -github.com/aws/aws-sdk-go-v2/service/route53 v1.45.0/go.mod h1:NAmFsZ4aGISCGa2nX+EGxPQGukb/z+XwriLW0i+EHKs= github.com/aws/aws-sdk-go-v2/service/route53 v1.45.2 h1:P4ElvGTPph12a87YpxPDIqCvVICeYJFV32UMMS/TIPc= github.com/aws/aws-sdk-go-v2/service/route53 v1.45.2/go.mod h1:zLKE53MjadFH0VYrDerAx25brxLYiSg4Vk3C+qPY4BQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.0 h1:71FvP6XFj53NK+YiAEGVzeiccLVeFnHOCvMig0zOHsE= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.0/go.mod h1:UVJqtKXSd9YppRKgdBIkyv7qgbSGv5DchM3yX0BN2mU= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2 h1:bSYXVyUzoTHoKalBmwaZxs97HU9DWWI3ehHSAMa7xOk= github.com/aws/aws-sdk-go-v2/service/sso v1.24.2/go.mod h1:skMqY7JElusiOUjMJMOv1jJsP7YUg7DrhgqZZWuzu1U= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.0 h1:Uco4o19bi3AmBapImNzuMk+rfzlui52BDyVK1UfJeRA= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.0/go.mod h1:+HLFhCpnG08hBee8bUdfd1mBK+rFKPt4O5igR9lXDfk= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2 h1:AhmO1fHINP9vFYUE0LHzCWg/LfUWUF+zFPEcY9QXb7o= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.2/go.mod h1:o8aQygT2+MVP0NaV6kbdE1YnnIM8RRVQzoeUH45GOdI= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.0 h1:GiQUjZM2KUZX68o/LpZ1xqxYMuvoxpRrOwYARYog3vc= -github.com/aws/aws-sdk-go-v2/service/sts v1.32.0/go.mod h1:dKnu7M4MAS2SDlng1ytxd03H+y0LoUfEQ5E2VaaSw/4= github.com/aws/aws-sdk-go-v2/service/sts v1.32.2 h1:CiS7i0+FUe+/YY1GvIBLLrR/XNGZ4CtM1Ll0XavNuVo= github.com/aws/aws-sdk-go-v2/service/sts v1.32.2/go.mod h1:HtaiBI8CjYoNVde8arShXb94UbQQi9L4EMr6D+xGBwo= github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= @@ -774,19 +738,21 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBW github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4= github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs= +github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c= +github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA= +github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0= +github.com/bsm/redislock v0.9.4 h1:X/Wse1DPpiQgHbVYRE9zv6m070UcKoOGekgvpNhiSvw= +github.com/bsm/redislock v0.9.4/go.mod h1:Epf7AJLiSFwLCiZcfi6pWFO/8eAYrYpQXFxEDPoDeAk= github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU= github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E= +github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw= github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= github.com/caarlos0/env/v11 v11.2.2 h1:95fApNrUyueipoZN/EhA8mMxiNxrBwDa+oAZrMWl3Kg= github.com/caarlos0/env/v11 v11.2.2/go.mod h1:JBfcdeQiBoI3Zh1QRAWfe+tpiNTmDtcCj/hHHHMx0vc= -github.com/casdoor/casdoor-go-sdk v0.52.0 h1:UKcZfczO3U5H7md6bTtI6zIJzeorBrbg/WE8Q4qsczE= -github.com/casdoor/casdoor-go-sdk v0.52.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4= -github.com/casdoor/casdoor-go-sdk v1.1.0 h1:QW1pMoGG18X+GrcMolKKaTXCLDOpoYCu2kbfUZZQ+5A= -github.com/casdoor/casdoor-go-sdk v1.1.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4= github.com/casdoor/casdoor-go-sdk v1.2.0 h1:DHLO8joZwgrAgdhhEZCPdrtLHdV89cXAa9UKxT7kwXg= github.com/casdoor/casdoor-go-sdk v1.2.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= @@ -794,7 +760,6 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -805,13 +770,9 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/civo/civogo v0.3.83 h1:GPLbSA4jJqCXCY291QO0jtr/k7jhkL+MgBT5bsgfPgc= -github.com/civo/civogo v0.3.83/go.mod h1:7UCYX+qeeJbrG55E1huv+0ySxcHTqq/26FcHLVelQJM= github.com/civo/civogo v0.3.84 h1:jf5IT7VJFPaReO6g8B0zqKhsYCIizaGo4PjDLY7Sl6Y= github.com/civo/civogo v0.3.84/go.mod h1:7UCYX+qeeJbrG55E1huv+0ySxcHTqq/26FcHLVelQJM= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.106.0 h1:q41gC5Wc1nfi0D1ZhSHokWcd9mGMbqC7RE7qiP+qE00= -github.com/cloudflare/cloudflare-go v0.106.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM= github.com/cloudflare/cloudflare-go v0.107.0 h1:cMDIw2tzt6TXCJyMFVyP+BPOVkIfMvcKjhMNSNvuEPc= github.com/cloudflare/cloudflare-go v0.107.0/go.mod h1:5cYGzVBqNTLxMYSLdVjuSs5LJL517wJDSvMPWUrzHzc= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= @@ -831,16 +792,19 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpu/goacmedns v0.1.1 h1:DM3H2NiN2oam7QljgGY5ygy4yDXhK5Z4JUnqaugs2C4= github.com/cpu/goacmedns v0.1.1/go.mod h1:MuaouqEhPAHxsbqjgnck5zeghuwBP1dLnPoobeGqugQ= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= @@ -853,6 +817,8 @@ github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88Nh github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +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/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= @@ -862,6 +828,8 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elliotchance/orderedmap/v2 v2.4.0 h1:6tUmMwD9F998FNpwFxA5E6NQvSpk2PVw7RKsVq3+2Cw= +github.com/elliotchance/orderedmap/v2 v2.4.0/go.mod h1:85lZyVbpGaGvHvnKa7Qhx7zncAdBIBq6u56Hb1PRU5Q= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -901,8 +869,6 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -918,6 +884,8 @@ github.com/go-acme/lego/v4 v4.19.2/go.mod h1:wtDe3dDkmV4/oI2nydpNXSJpvV10J9RCyZ6 github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= +github.com/go-co-op/gocron/v2 v2.12.1 h1:dCIIBFbzhWKdgXeEifBjHPzgQ1hoWhjS4289Hjjy1uw= +github.com/go-co-op/gocron/v2 v2.12.1/go.mod h1:xY7bJxGazKam1cz04EebrlP4S9q4iWdiAylMGP3jY9w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= @@ -984,6 +952,7 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -1193,10 +1162,6 @@ github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/J github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.116 h1:2xdw38EHrdkciWjRdwd75p6a+cXe4PxWSgHMNYMbQnI= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.116/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.117 h1:TUiy5+4+Q7AWNfvKjQQL6lXOylnp7HL47JyYJ+HgN+I= -github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.117/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI= github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.118 h1:YHcixaT7Le4PxuxN07KQ5j9nPeH4ZdyXtMTSgA+Whh8= github.com/huaweicloud/huaweicloud-sdk-go-v3 v0.1.118/go.mod h1:JWz2ujO9X3oU5wb6kXp+DpR2UuDj2SldDbX8T0FSuhI= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= @@ -1210,14 +1175,62 @@ github.com/infobloxopen/infoblox-go-client v1.1.1 h1:728A6LbLjptj/7kZjHyIxQnm768 github.com/infobloxopen/infoblox-go-client v1.1.1/go.mod h1:BXiw7S2b9qJoM8MS40vfgCNB2NLHGusk1DtO16BD9zI= github.com/itchyny/timefmt-go v0.1.6 h1:ia3s54iciXDdzWzwaVKXZPbiXzxxnv1SPGFfM/myJ5Q= github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJGxm9/mAERQg= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= +github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= +github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= +github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= +github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= +github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= +github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= +github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= +github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= +github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= -github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= +github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= +github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= +github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= +github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= +github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= +github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= +github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.4 h1:fKuNiCumbKTAIxQwXfB/nsrnkEI6bPJrrSiMKgbJ2j8= +github.com/jackc/pgtype v1.14.4/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= +github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= +github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= +github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= +github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= +github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jarcoal/httpmock v1.0.8/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= @@ -1230,6 +1243,8 @@ github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHW github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jpillora/overseer v1.1.6 h1:3ygYfNcR3FfOr22miu3vR1iQcXKMHbmULBh98rbkIyo= github.com/jpillora/overseer v1.1.6/go.mod h1:aPXQtxuVb9PVWRWTXpo+LdnC/YXQ0IBLNXqKMJmgk88= @@ -1252,6 +1267,8 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= @@ -1265,6 +1282,7 @@ github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgSh github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00= github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -1275,6 +1293,7 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -1286,6 +1305,10 @@ github.com/labbsr0x/goh v1.0.1 h1:97aBJkDjpyBZGPbQuOK5/gHcSFbcr5aRsq3RSRJFpPk= github.com/labbsr0x/goh v1.0.1/go.mod h1:8K2UhVoaWXcCU7Lxoa2omWnC8gyW8px7/lmO61c027w= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/linode/linodego v1.41.0 h1:GcP7JIBr9iLRJ9FwAtb9/WCT1DuPJS/xUApapfdjtiY= @@ -1307,6 +1330,7 @@ github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -1316,6 +1340,8 @@ github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= @@ -1423,10 +1449,6 @@ github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A= github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU= -github.com/oracle/oci-go-sdk/v65 v65.75.1 h1:c7U7WQWeWZdPpzbsxf8dNRd4jXkyTNCNKaCAndvjTqw= -github.com/oracle/oci-go-sdk/v65 v65.75.1/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= -github.com/oracle/oci-go-sdk/v65 v65.75.2 h1:Qw3Eotrq7SJ5LquOc//Iq6xzcBJSi8AD3cXps9IBN7g= -github.com/oracle/oci-go-sdk/v65 v65.75.2/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= github.com/oracle/oci-go-sdk/v65 v65.76.0 h1:mecdD9at/CMaQNEkcC5aMUR9aBF3brdiEyVkDRu/qVc= github.com/oracle/oci-go-sdk/v65 v65.76.0/go.mod h1:IBEV9l1qBzUpo7zgGaRUhbB05BVfcDGYRFBCPlTcPp0= github.com/ovh/go-ovh v1.6.0 h1:ixLOwxQdzYDx296sXcgS35TOPEahJkpjMGtzPadCjQI= @@ -1493,6 +1515,8 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/redis/go-redis/v9 v9.7.0 h1:HhLSs+B6O021gwzl+locl0zEDnyNkxMtf/Z3NNBMa9E= +github.com/redis/go-redis/v9 v9.7.0/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= @@ -1504,6 +1528,9 @@ github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= +github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= @@ -1525,12 +1552,9 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= -github.com/sashabaranov/go-openai v1.31.0 h1:rGe77x7zUeCjtS2IS7NCY6Tp4bQviXNMhkQM6hz/UC4= -github.com/sashabaranov/go-openai v1.31.0/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= -github.com/sashabaranov/go-openai v1.32.1 h1:JmdOa6d+cQwvGpBJigQf+dq40Qc20b+1HcXRGVOmqFw= -github.com/sashabaranov/go-openai v1.32.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/sashabaranov/go-openai v1.32.2 h1:8z9PfYaLPbRzmJIYpwcWu6z3XU8F+RwVMF1QRSeSF2M= github.com/sashabaranov/go-openai v1.32.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30 h1:yoKAVkEVwAqbGbR8n87rHQ1dulL25rKloGadb3vm770= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30/go.mod h1:sH0u6fq6x4R5M7WxkoQFY/o7UaiItec0o1LinLCJNq8= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -1544,10 +1568,13 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= @@ -1568,6 +1595,8 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/sony/gobreaker v0.5.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/sony/sonyflake v1.2.0 h1:Pfr3A+ejSg+0SPqpoAmQgEtNDAhc2G1SUYk205qVMLQ= +github.com/sony/sonyflake v1.2.0/go.mod h1:LORtCywH/cq10ZbyfhKrHYgAUGH7mOBa76enV9txy/Y= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -1598,6 +1627,7 @@ github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= @@ -1621,16 +1651,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1015 h1:O60uxxfWztVPVUBQjlJaop2Dw/J7CXGK9fSErMdWw+Y= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1015/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1021 h1:PziIST/T1MUZHQwCKpF+CX9FmBeTd3J6EJNbhtB31xI= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1021/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1026 h1:6iBtl1CunsfWcT6IyCuRdgefJ/Zmsp5MTDujnolyuQs= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1026/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1015 h1:D+umrlpUPSDOiSLGIgPECIJ8Rrary9m7aFYnznbE/lM= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1015/go.mod h1:QpUpIeygPrCIBKYX2gWvRFo7fdGHs3faTNFlmePVo3g= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1021 h1:dijBHnKKmOoE6lDKGwmT4mPtmC/JVX8TrJkcyH5ioDU= -github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1021/go.mod h1:zAlqm80JiBwcsJXEczgRtCvJxoT2HC3ZndyvKjP/uis= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1026 h1:W6wPKS41uNKs7RBcJP5iB0HrcglXNSFUmnQaBEorVpg= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1026/go.mod h1:aqLJU0aRU1k7l+TPyYCao+KQHrFEF6lNQqK04FIiLJw= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= @@ -1653,14 +1675,18 @@ github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVK github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/ultradns/ultradns-go-sdk v1.7.0-20240913052650-970ca9a h1:R6IR+Vj/RnGZLnX8PpPQsbbQthctO7Ah2q4tj5eoe2o= -github.com/ultradns/ultradns-go-sdk v1.7.0-20240913052650-970ca9a/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss= github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+UzD/hf3P4Gd1j0JI9ncbxv+nsypPoUYI= github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss= +github.com/uozi-tech/cosy v1.9.4 h1:oG5TbrS8XUpZnQ++9gxI5if0++uJ7h9nMPZPNeDgly0= +github.com/uozi-tech/cosy v1.9.4/go.mod h1:aQI/OU3EVF125K5ECgSg3+CTfG4cp5XOkr++DEP/Fas= +github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo= +github.com/uozi-tech/cosy-driver-mysql v0.2.2/go.mod h1:EZnRIbSj1V5U0gEeTobrXai/d1SV11lkl4zP9NFEmyE= +github.com/uozi-tech/cosy-driver-postgres v0.2.1 h1:OICakGuT+omva6QOJCxTJ5Lfr7CGXLmk/zD+aS51Z2o= +github.com/uozi-tech/cosy-driver-postgres v0.2.1/go.mod h1:eAy1A89yHbAEfjkhNAifaJQk172NqrNoRyRtFcZc9Go= +github.com/uozi-tech/cosy-driver-sqlite v0.2.0 h1:eTpIMyGoFUK4JcaiKfJHD5AyiM6vtCwN98c7Bz5n25o= +github.com/uozi-tech/cosy-driver-sqlite v0.2.0/go.mod h1:87a6mzn5IuEtIR4z7U4Ey8eKLGfNEOSkv7kPQlbNQgM= github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ= github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q= -github.com/vultr/govultr/v3 v3.9.1 h1:uxSIb8Miel7tqTs3ee+z3t+JelZikwqBBsZzCOPBy/8= -github.com/vultr/govultr/v3 v3.9.1/go.mod h1:Rd8ebpXm7jxH3MDmhnEs+zrlYW212ouhx+HeUMfHm2o= github.com/vultr/govultr/v3 v3.10.0 h1:NjtFMcccmP2+5EXb5dEamwwrdeJjzzc8iAsPWOuAyao= github.com/vultr/govultr/v3 v3.10.0/go.mod h1:q34Wd76upKmf+vxFMgaNMH3A8BbsPBmSYZUGC8oZa5w= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -1672,16 +1698,8 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/yandex-cloud/go-genproto v0.0.0-20241004153110-80386e3567fa h1:OEaAUuoBdU7Opsk/JP4KlNe8YCphmMr4ibyYIOAzAKE= -github.com/yandex-cloud/go-genproto v0.0.0-20241004153110-80386e3567fa/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo= -github.com/yandex-cloud/go-genproto v0.0.0-20241014130938-6bcc214f8c09 h1:yPngbVL7P9+BAA/F4ekNHW+Fxw+XhztG809lhlU7Yvk= -github.com/yandex-cloud/go-genproto v0.0.0-20241014130938-6bcc214f8c09/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo= github.com/yandex-cloud/go-genproto v0.0.0-20241018072940-69706eaae3be h1:jGNL9PedKrHWl1WCRdlBEFo7nDl589LKvkulZRf7ZTA= github.com/yandex-cloud/go-genproto v0.0.0-20241018072940-69706eaae3be/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo= -github.com/yandex-cloud/go-sdk v0.0.0-20240919120105-e63f9f4339a3 h1:t4T2EYu9LCNGYYjJA8x/ZIn8PHzJIxghjEGa9+Cx4xg= -github.com/yandex-cloud/go-sdk v0.0.0-20240919120105-e63f9f4339a3/go.mod h1:RI42kDbwc4lOD8MtWmJDji5N/1P4AEToQQAprJby6XU= -github.com/yandex-cloud/go-sdk v0.0.0-20241007112728-a06ce15e89c7 h1:pnIBO/B6vz9+JnHXGdxdAJ5OJePKEPccYJiFvKbTr1Y= -github.com/yandex-cloud/go-sdk v0.0.0-20241007112728-a06ce15e89c7/go.mod h1:OISl+xMxmCNom9wbLTwfOWvlS9uu+PpdjKhXKYsXSgE= github.com/yandex-cloud/go-sdk v0.0.0-20241018073342-0142f4806660 h1:/XDcP3XiGxwW6GGYzjHtQ82ZEEdpCuDQlmmsmx6Zyuc= github.com/yandex-cloud/go-sdk v0.0.0-20241018073342-0142f4806660/go.mod h1:7Ru6CfLQ1pfa5WcWdzdr8UY7xRsvVTykxBh5dzjx+Ic= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= @@ -1696,6 +1714,7 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= +github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA= go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k= @@ -1715,26 +1734,21 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= -go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= -go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc= go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= -go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w= -go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ= go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= -go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc= -go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o= go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -1743,13 +1757,18 @@ go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/ratelimit v0.3.1 h1:K4qVE+byfv/B3tC+4nYWP7v/6SimcO7HzHekoMNBma0= go.uber.org/ratelimit v0.3.1/go.mod h1:6euWsTB6U/Nb3X++xEUXA8ciPJvr19Q/0h1+oDcJhRk= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= @@ -1759,6 +1778,7 @@ golang.org/x/arch v0.11.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1767,8 +1787,11 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -1782,6 +1805,7 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= @@ -1800,8 +1824,6 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6 h1:1wqE9dj9NpSm04INVsJhhEUzhuDVjbcyKH91sVyPATw= -golang.org/x/exp v0.0.0-20241004190924-225e2abe05e6/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= @@ -1866,6 +1888,7 @@ golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1983,6 +2006,7 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1991,6 +2015,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -2148,16 +2173,20 @@ golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -2166,6 +2195,7 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -2208,6 +2238,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2282,10 +2314,6 @@ google.golang.org/api v0.110.0/go.mod h1:7FC4Vvx1Mooxh8C5HWjzZHcavuS2f6pmJpZx60c google.golang.org/api v0.111.0/go.mod h1:qtFHvU9mhgTJegR31csQ+rwxyUTHOKFqCKWp1J0fdw0= google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45N5Yg= google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms= -google.golang.org/api v0.199.0 h1:aWUXClp+VFJmqE0JPvpZOK3LDQMyFKYIow4etYd9qxs= -google.golang.org/api v0.199.0/go.mod h1:ohG4qSztDJmZdjK/Ar6MhbAmb/Rpi4JHOqagsh90K28= -google.golang.org/api v0.200.0 h1:0ytfNWn101is6e9VBoct2wrGDjOi5vn7jw5KtaQgDrU= -google.golang.org/api v0.200.0/go.mod h1:Tc5u9kcbjO7A8SwGlYj4IiVifJU01UqXtEgDMYmBmV8= google.golang.org/api v0.201.0 h1:+7AD9JNM3tREtawRMu8sOjSbb8VYcYXJG/2eEOmfDu0= google.golang.org/api v0.201.0/go.mod h1:HVY0FCHVs89xIW9fzf/pBvOEm+OolHa86G/txFezyq4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -2427,22 +2455,10 @@ google.golang.org/genproto v0.0.0-20230323212658-478b75c54725/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230330154414-c0448cd141ea/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak= google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/genproto v0.0.0-20240930140551-af27646dc61f h1:mCJ6SGikSxVlt9scCayUl2dMq0msUgmBArqRY6umieI= -google.golang.org/genproto v0.0.0-20240930140551-af27646dc61f/go.mod h1:xtVODtPkMQRUZ4kqOTgp6JrXQrPevvfCSdk4mJtHUbM= -google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9 h1:nFS3IivktIU5Mk6KQa+v6RKkHUpdQpphqGNLxqNnbEk= -google.golang.org/genproto v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:tEzYTYZxbmVNOu0OAFH9HzdJtLn6h4Aj89zzlBCdHms= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= -google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f h1:jTm13A2itBi3La6yTGqn8bVSrc3ZZ1r8ENHlIXBfnRA= -google.golang.org/genproto/googleapis/api v0.0.0-20240930140551-af27646dc61f/go.mod h1:CLGoBuH1VHxAUXVPP8FfPwPEVJB6lz3URE5mY2SuayE= -google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= -google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f h1:cUMEy+8oS78BWIH9OWazBkzbr090Od9tWBNtZHkOhf0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240930140551-af27646dc61f/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9 h1:QCqS/PdaHTSWGvupk2F/ehwHtGc0/GYkT+3GAcR1CCc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -2507,8 +2523,6 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -2525,6 +2539,7 @@ gopkg.in/guregu/null.v4 v4.0.0 h1:1Wm3S1WEA2I26Kq+6vcW+w0gcDo44YKYD7YIEJNHDjg= gopkg.in/guregu/null.v4 v4.0.0/go.mod h1:YoQhUrADuG3i9WqesrCmpNRwm1ypAgSHYqoOcTu/JrI= gopkg.in/h2non/gock.v1 v1.0.15 h1:SzLqcIlb/fDfg7UvukMpNcWsu7sI5tWwL+KCATZqks0= gopkg.in/h2non/gock.v1 v1.0.15/go.mod h1:sX4zAkdYX1TRGJ2JY156cFspQn4yRWn6p9EMdODlynE= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -2532,8 +2547,6 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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/ns1/ns1-go.v2 v2.12.1 h1:GiiZPB8JusUF/ruyUDzddd70b3HZGa5A3njtKUe84jA= -gopkg.in/ns1/ns1-go.v2 v2.12.1/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc= gopkg.in/ns1/ns1-go.v2 v2.12.2 h1:SPM5BTTMJ1zVBhMMiiPFdF7l6Y3fq5o7bKM7jDqsUfM= gopkg.in/ns1/ns1-go.v2 v2.12.2/go.mod h1:pfaU0vECVP7DIOr453z03HXS6dFJpXdNRwOyRzwmPSc= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -2554,16 +2567,12 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0/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= -gorm.io/datatypes v1.2.2 h1:sdn7ZmG4l7JWtMDUb3L98f2Ym7CO5F8mZLlrQJMfF9g= -gorm.io/datatypes v1.2.2/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI= -gorm.io/datatypes v1.2.3 h1:95ucr9ip9dZMPhB3Tc9zbcoAi62hxYAgHicu7SLjK4g= -gorm.io/datatypes v1.2.3/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI= gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4= gorm.io/datatypes v1.2.4/go.mod h1:f4BsLcFAX67szSv8svwLRjklArSHAvHLeE3pXAS5DZI= gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= -gorm.io/driver/postgres v1.5.6 h1:ydr9xEd5YAM0vxVDY0X139dyzNz10spDiDlC7+ibLeU= -gorm.io/driver/postgres v1.5.6/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= +gorm.io/driver/postgres v1.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8= +gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I= gorm.io/driver/sqlite v1.5.6 h1:fO/X46qn5NUEEOZtnjJRWRzZMe8nqJiQ9E+0hi+hKQE= gorm.io/driver/sqlite v1.5.6/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4= @@ -2637,8 +2646,6 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= diff --git a/img.png b/img.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c9d3fbd826974d2279bd7afc8f90e6e1910649 GIT binary patch literal 40441 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 YMH9ZEzc%n|G690VXl78Q?-uj_0O$VRU;qFB literal 0 HcmV?d00001 diff --git a/install.sh b/install.sh index eb968cf3..715a5738 100644 --- a/install.sh +++ b/install.sh @@ -290,9 +290,12 @@ install_config() { if [[ ! -f "$DataPath/app.ini" ]]; then cat > "$DataPath/app.ini" << EOF [server] +HOST = 127.0.0.1 +PORT = 9000 RunMode = release -HttpPort = 9000 -HTTPChallengePort = 9180 + +[cert] +HTTPChallengePort = 9180 EOF echo "info: The default configuration file was installed to '$DataPath/app.ini' successfully!" fi diff --git a/internal/analytic/analytic.go b/internal/analytic/analytic.go index a5a26461..1e8f0b60 100644 --- a/internal/analytic/analytic.go +++ b/internal/analytic/analytic.go @@ -1,7 +1,7 @@ package analytic import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/shirou/gopsutil/v3/net" "time" ) diff --git a/internal/analytic/node.go b/internal/analytic/node.go index 16c8c232..57ba06a4 100644 --- a/internal/analytic/node.go +++ b/internal/analytic/node.go @@ -2,7 +2,7 @@ package analytic import ( "encoding/json" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/transport" "github.com/0xJacky/Nginx-UI/internal/upgrader" "github.com/0xJacky/Nginx-UI/model" diff --git a/internal/analytic/node_record.go b/internal/analytic/node_record.go index 65da0c64..9aabfc32 100644 --- a/internal/analytic/node_record.go +++ b/internal/analytic/node_record.go @@ -3,7 +3,7 @@ package analytic import ( "context" "encoding/json" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/gorilla/websocket" diff --git a/internal/analytic/node_stat.go b/internal/analytic/node_stat.go index 7a46d08e..beb0964c 100644 --- a/internal/analytic/node_stat.go +++ b/internal/analytic/node_stat.go @@ -1,7 +1,7 @@ package analytic import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/load" "github.com/shirou/gopsutil/v3/net" diff --git a/internal/analytic/record.go b/internal/analytic/record.go index bd941241..8bdf6f51 100644 --- a/internal/analytic/record.go +++ b/internal/analytic/record.go @@ -1,7 +1,7 @@ package analytic import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/shirou/gopsutil/v3/cpu" "github.com/shirou/gopsutil/v3/disk" "github.com/shirou/gopsutil/v3/net" diff --git a/internal/cache/cache.go b/internal/cache/cache.go index 597cfe7d..f8a9d4d9 100644 --- a/internal/cache/cache.go +++ b/internal/cache/cache.go @@ -1,7 +1,7 @@ package cache import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/dgraph-io/ristretto" "time" ) diff --git a/internal/cert/auto_cert.go b/internal/cert/auto_cert.go index c1c96e01..8a5c73d7 100644 --- a/internal/cert/auto_cert.go +++ b/internal/cert/auto_cert.go @@ -1,11 +1,11 @@ package cert import ( - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/notification" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/settings" "github.com/pkg/errors" + "github.com/uozi-tech/cosy/logger" "runtime" "strings" "time" @@ -60,8 +60,8 @@ func autoCert(certModel *model.Cert) { notification.Error("Renew Certificate Error", strings.Join(certModel.Domains, ", ")) return } - if int(time.Now().Sub(certInfo.NotBefore).Hours()/24) < settings.ServerSettings.GetCertRenewalInterval() { - // not after settings.ServerSettings.CertRenewalInterval, ignore + if int(time.Now().Sub(certInfo.NotBefore).Hours()/24) < settings.CertSettings.GetCertRenewalInterval() { + // not after settings.ServerSettings.RenewalInterval, ignore return } diff --git a/internal/cert/cert.go b/internal/cert/cert.go index 0a1efd1d..b88cf8d4 100644 --- a/internal/cert/cert.go +++ b/internal/cert/cert.go @@ -2,7 +2,6 @@ package cert import ( "github.com/0xJacky/Nginx-UI/internal/cert/dns" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/internal/transport" "github.com/0xJacky/Nginx-UI/query" @@ -13,6 +12,7 @@ import ( legolog "github.com/go-acme/lego/v4/log" dnsproviders "github.com/go-acme/lego/v4/providers/dns" "github.com/pkg/errors" + "github.com/uozi-tech/cosy/logger" "log" "os" "time" @@ -87,7 +87,7 @@ func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error) l.Println("[INFO] [Nginx UI] Setting HTTP01 challenge provider") err = client.Challenge.SetHTTP01Provider( http01.NewProviderServer("", - settings.ServerSettings.HTTPChallengePort, + settings.CertSettings.HTTPChallengePort, ), ) case DNS01: @@ -125,9 +125,9 @@ func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error) } challengeOptions := make([]dns01.ChallengeOption, 0) - if len(settings.ServerSettings.RecursiveNameservers) > 0 { + if len(settings.CertSettings.RecursiveNameservers) > 0 { challengeOptions = append(challengeOptions, - dns01.AddRecursiveNameservers(settings.ServerSettings.RecursiveNameservers), + dns01.AddRecursiveNameservers(settings.CertSettings.RecursiveNameservers), ) } diff --git a/internal/cert/logger.go b/internal/cert/logger.go index 8c84116a..81323bb9 100644 --- a/internal/cert/logger.go +++ b/internal/cert/logger.go @@ -2,7 +2,7 @@ package cert import ( "fmt" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/model" "strings" "time" diff --git a/internal/cert/payload.go b/internal/cert/payload.go index 8127668a..781123e4 100644 --- a/internal/cert/payload.go +++ b/internal/cert/payload.go @@ -2,7 +2,7 @@ package cert import ( "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" diff --git a/internal/cert/register.go b/internal/cert/register.go index 3cddd7ea..82f621f6 100644 --- a/internal/cert/register.go +++ b/internal/cert/register.go @@ -1,23 +1,25 @@ package cert import ( - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" "github.com/pkg/errors" + "github.com/uozi-tech/cosy/logger" "gorm.io/gorm" ) // InitRegister init the default user for acme func InitRegister() { - if settings.ServerSettings.Email == "" { + email := settings.CertSettings.Email + if settings.CertSettings.Email == "" { return } + caDir := settings.CertSettings.GetCADir() u := query.AcmeUser - _, err := u.Where(u.Email.Eq(settings.ServerSettings.Email), - u.CADir.Eq(settings.ServerSettings.GetCADir())).First() + _, err := u.Where(u.Email.Eq(email), + u.CADir.Eq(caDir)).First() if err == nil { return @@ -31,8 +33,8 @@ func InitRegister() { // Create a new user user := &model.AcmeUser{ Name: "System Initial User", - Email: settings.ServerSettings.Email, - CADir: settings.ServerSettings.GetCADir(), + Email: email, + CADir: caDir, } err = user.Register() @@ -52,8 +54,8 @@ func InitRegister() { func GetDefaultACMEUser() (user *model.AcmeUser, err error) { u := query.AcmeUser - user, err = u.Where(u.Email.Eq(settings.ServerSettings.Email), - u.CADir.Eq(settings.ServerSettings.GetCADir())).First() + user, err = u.Where(u.Email.Eq(settings.CertSettings.Email), + u.CADir.Eq(settings.CertSettings.GetCADir())).First() if err != nil { err = errors.Wrap(err, "get default user error") diff --git a/internal/cert/sync.go b/internal/cert/sync.go index 9991e69a..b03cb9ec 100644 --- a/internal/cert/sync.go +++ b/internal/cert/sync.go @@ -5,7 +5,7 @@ import ( "encoding/json" "fmt" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/internal/notification" "github.com/0xJacky/Nginx-UI/internal/transport" diff --git a/internal/chatbot/context.go b/internal/chatbot/context.go index f2703815..cbc3bf5c 100644 --- a/internal/chatbot/context.go +++ b/internal/chatbot/context.go @@ -2,7 +2,7 @@ package chatbot import ( "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/sashabaranov/go-openai" "os" diff --git a/internal/cluster/cluster.go b/internal/cluster/cluster.go index b7ff216f..0309855b 100644 --- a/internal/cluster/cluster.go +++ b/internal/cluster/cluster.go @@ -1,7 +1,7 @@ package cluster import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" diff --git a/internal/config/sync.go b/internal/config/sync.go index 76080815..8828a25a 100644 --- a/internal/config/sync.go +++ b/internal/config/sync.go @@ -6,7 +6,6 @@ import ( "encoding/json" "fmt" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/internal/notification" "github.com/0xJacky/Nginx-UI/internal/transport" @@ -14,6 +13,7 @@ import ( "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-gonic/gin" + "github.com/uozi-tech/cosy/logger" "io" "net/http" "os" @@ -205,7 +205,7 @@ func (p *RenameConfigPayload) rename(env *model.Environment) (err error) { client := http.Client{ Transport: &http.Transport{ - TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify}, + TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.HTTPSettings.InsecureSkipVerify}, }, } diff --git a/internal/cosy/cosy.go b/internal/cosy/cosy.go deleted file mode 100644 index 282b6f59..00000000 --- a/internal/cosy/cosy.go +++ /dev/null @@ -1,117 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/internal/logger" - "github.com/gin-gonic/gin" - "github.com/go-playground/validator/v10" - "gorm.io/gorm" -) - -var validate *validator.Validate - -func init() { - validate = validator.New() -} - -type Ctx[T any] struct { - ctx *gin.Context - rules gin.H - Payload map[string]interface{} - Model T - OriginModel T - table string - tableArgs []interface{} - abort bool - nextHandler *gin.HandlerFunc - skipAssociationsOnCreate bool - beforeDecodeHookFunc []func(ctx *Ctx[T]) - beforeExecuteHookFunc []func(ctx *Ctx[T]) - executedHookFunc []func(ctx *Ctx[T]) - gormScopes []func(tx *gorm.DB) *gorm.DB - preloads []string - scan func(tx *gorm.DB) any - transformer func(*T) any - permanentlyDelete bool - SelectedFields []string - itemKey string -} - -func Core[T any](c *gin.Context) *Ctx[T] { - return &Ctx[T]{ - ctx: c, - gormScopes: make([]func(tx *gorm.DB) *gorm.DB, 0), - beforeExecuteHookFunc: make([]func(ctx *Ctx[T]), 0), - beforeDecodeHookFunc: make([]func(ctx *Ctx[T]), 0), - itemKey: "`id`", - skipAssociationsOnCreate: true, - } -} - -func (c *Ctx[T]) SetTable(table string, args ...interface{}) *Ctx[T] { - c.table = table - c.tableArgs = args - return c -} - -func (c *Ctx[T]) SetItemKey(key string) *Ctx[T] { - c.itemKey = key - return c -} - -func (c *Ctx[T]) SetValidRules(rules gin.H) *Ctx[T] { - c.rules = rules - - return c -} - -func (c *Ctx[T]) SetPreloads(args ...string) *Ctx[T] { - c.preloads = append(c.preloads, args...) - return c -} - -func (c *Ctx[T]) validate() (errs gin.H) { - c.Payload = make(gin.H) - - _ = c.ctx.ShouldBindJSON(&c.Payload) - - errs = validate.ValidateMap(c.Payload, c.rules) - - if len(errs) > 0 { - logger.Debug(errs) - for k := range errs { - errs[k] = c.rules[k] - } - return - } - // Make sure that the key in c.Payload is also the key of rules - validated := make(map[string]interface{}) - - for k, v := range c.Payload { - if _, ok := c.rules[k]; ok { - validated[k] = v - } - } - - c.Payload = validated - - return -} - -func (c *Ctx[T]) SetScan(scan func(tx *gorm.DB) any) *Ctx[T] { - c.scan = scan - return c -} - -func (c *Ctx[T]) SetTransformer(t func(m *T) any) *Ctx[T] { - c.transformer = t - return c -} - -func (c *Ctx[T]) AbortWithError(err error) { - c.abort = true - errHandler(c.ctx, err) -} - -func (c *Ctx[T]) Abort() { - c.abort = true -} diff --git a/internal/cosy/create.go b/internal/cosy/create.go deleted file mode 100644 index b29ae7c4..00000000 --- a/internal/cosy/create.go +++ /dev/null @@ -1,81 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/internal/cosy/map2struct" - "github.com/0xJacky/Nginx-UI/model" - "github.com/gin-gonic/gin" - "gorm.io/gorm/clause" - "net/http" -) - -func (c *Ctx[T]) Create() { - - errs := c.validate() - - if len(errs) > 0 { - c.ctx.JSON(http.StatusNotAcceptable, gin.H{ - "message": "Requested with wrong parameters", - "errors": errs, - }) - return - } - - db := model.UseDB() - - c.beforeDecodeHook() - - if c.abort { - return - } - - err := map2struct.WeakDecode(c.Payload, &c.Model) - - if err != nil { - errHandler(c.ctx, err) - return - } - - c.beforeExecuteHook() - - if c.abort { - return - } - - if c.skipAssociationsOnCreate { - err = db.Omit(clause.Associations).Create(&c.Model).Error - } else { - err = db.Create(&c.Model).Error - } - - if err != nil { - errHandler(c.ctx, err) - return - } - - if len(c.executedHookFunc) > 0 { - for _, v := range c.executedHookFunc { - v(c) - - if c.abort { - return - } - } - } - - tx := db.Preload(clause.Associations) - for _, v := range c.preloads { - tx = tx.Preload(v) - } - tx.Table(c.table, c.tableArgs...).First(&c.Model) - - if c.nextHandler != nil { - (*c.nextHandler)(c.ctx) - } else { - c.ctx.JSON(http.StatusOK, c.Model) - } -} - -func (c *Ctx[T]) WithAssociations() *Ctx[T] { - c.skipAssociationsOnCreate = false - return c -} diff --git a/internal/cosy/custom.go b/internal/cosy/custom.go deleted file mode 100644 index 5fd847be..00000000 --- a/internal/cosy/custom.go +++ /dev/null @@ -1,39 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/internal/cosy/map2struct" - "github.com/gin-gonic/gin" - "net/http" -) - -func (c *Ctx[T]) Custom(fx func(ctx *Ctx[T])) { - if c.abort { - return - } - errs := c.validate() - - if len(errs) > 0 { - c.ctx.JSON(http.StatusNotAcceptable, gin.H{ - "message": "Requested with wrong parameters", - "errors": errs, - }) - return - } - - c.beforeDecodeHook() - - for k := range c.Payload { - c.SelectedFields = append(c.SelectedFields, k) - } - - err := map2struct.WeakDecode(c.Payload, &c.Model) - - if err != nil { - errHandler(c.ctx, err) - return - } - - c.beforeExecuteHook() - - fx(c) -} diff --git a/internal/cosy/delete.go b/internal/cosy/delete.go deleted file mode 100644 index 82b0e7c6..00000000 --- a/internal/cosy/delete.go +++ /dev/null @@ -1,113 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/model" - "github.com/spf13/cast" - "gorm.io/gorm" - "net/http" -) - -func (c *Ctx[T]) PermanentlyDelete() { - c.permanentlyDelete = true - c.Destroy() -} - -func (c *Ctx[T]) Destroy() { - if c.abort { - return - } - id := c.ctx.Param("id") - - c.beforeExecuteHook() - - db := model.UseDB() - - result := db - - if cast.ToBool(c.ctx.Query("permanent")) || c.permanentlyDelete { - result = result.Unscoped() - } - - if len(c.gormScopes) > 0 { - result = result.Scopes(c.gormScopes...) - } - - var err error - session := result.Session(&gorm.Session{}) - if c.table != "" { - err = session.Table(c.table, c.tableArgs...).Take(c.OriginModel, id).Error - } else { - err = session.First(&c.OriginModel, id).Error - } - - if err != nil { - errHandler(c.ctx, err) - return - } - - err = result.Delete(&c.OriginModel).Error - if err != nil { - errHandler(c.ctx, err) - return - } - - if len(c.executedHookFunc) > 0 { - for _, v := range c.executedHookFunc { - v(c) - - if c.abort { - return - } - } - } - - c.ctx.JSON(http.StatusNoContent, nil) -} - -func (c *Ctx[T]) Recover() { - if c.abort { - return - } - id := c.ctx.Param("id") - - c.beforeExecuteHook() - - db := model.UseDB() - var dbModel T - - result := db.Unscoped() - if len(c.gormScopes) > 0 { - result = result.Scopes(c.gormScopes...) - } - - var err error - session := result.Session(&gorm.Session{}) - if c.table != "" { - err = session.Table(c.table).Take(&dbModel, id).Error - } else { - err = session.First(&dbModel, id).Error - } - - if err != nil { - errHandler(c.ctx, err) - return - } - - err = result.Model(&dbModel).Update("deleted_at", nil).Error - if err != nil { - errHandler(c.ctx, err) - return - } - - if len(c.executedHookFunc) > 0 { - for _, v := range c.executedHookFunc { - v(c) - - if c.abort { - return - } - } - } - - c.ctx.JSON(http.StatusNoContent, nil) -} diff --git a/internal/cosy/error.go b/internal/cosy/error.go deleted file mode 100644 index caa5a5ba..00000000 --- a/internal/cosy/error.go +++ /dev/null @@ -1,23 +0,0 @@ -package cosy - -import ( - "errors" - "github.com/0xJacky/Nginx-UI/internal/logger" - "github.com/gin-gonic/gin" - "go.uber.org/zap" - "gorm.io/gorm" - "net/http" -) - -func errHandler(c *gin.Context, err error) { - logger.GetLogger().WithOptions(zap.AddCallerSkip(1)).Errorln(err) - if errors.Is(err, gorm.ErrRecordNotFound) { - c.JSON(http.StatusNotFound, gin.H{ - "message": err.Error(), - }) - return - } - c.JSON(http.StatusInternalServerError, gin.H{ - "message": err.Error(), - }) -} diff --git a/internal/cosy/filter.go b/internal/cosy/filter.go deleted file mode 100644 index 25bd36fc..00000000 --- a/internal/cosy/filter.go +++ /dev/null @@ -1,212 +0,0 @@ -package cosy - -import ( - "fmt" - "github.com/0xJacky/Nginx-UI/internal/logger" - "github.com/gin-gonic/gin" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "strings" -) - -func (c *Ctx[T]) SetFussy(keys ...string) *Ctx[T] { - c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB { - return QueryToFussySearch(c.ctx, tx, keys...) - }) - return c -} - -func (c *Ctx[T]) SetFussyKeys(value string, keys ...string) *Ctx[T] { - c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB { - return QueryToFussyKeysSearch(c.ctx, tx, value, keys...) - }) - return c -} - -func (c *Ctx[T]) SetEqual(keys ...string) *Ctx[T] { - c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB { - return QueryToEqualSearch(c.ctx, tx, keys...) - }) - return c -} - -func (c *Ctx[T]) SetIn(keys ...string) *Ctx[T] { - c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB { - return QueryToInSearch(c.ctx, tx, keys...) - }) - return c -} - -func (c *Ctx[T]) SetOrFussy(keys ...string) *Ctx[T] { - c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB { - return QueryToOrFussySearch(c.ctx, tx, keys...) - }) - return c -} - -func (c *Ctx[T]) SetOrEqual(keys ...string) *Ctx[T] { - c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB { - return QueryToOrEqualSearch(c.ctx, tx, keys...) - }) - return c -} - -func (c *Ctx[T]) SetOrIn(keys ...string) *Ctx[T] { - c.gormScopes = append(c.gormScopes, func(tx *gorm.DB) *gorm.DB { - return QueryToOrInSearch(c.ctx, tx, keys...) - }) - return c -} - -func QueryToInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB { - for _, v := range keys { - queryArray := c.QueryArray(v + "[]") - if len(queryArray) == 0 { - queryArray = c.QueryArray(v) - } - if len(queryArray) == 1 && queryArray[0] == "" { - continue - } - if len(queryArray) >= 1 { - var builder strings.Builder - stmt := db.Statement - - stmt.QuoteTo(&builder, clause.Column{Table: stmt.Table, Name: v}) - builder.WriteString(" IN ?") - - db = db.Where(builder.String(), queryArray) - } - } - return db -} - -func QueryToEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB { - for _, v := range keys { - if c.Query(v) != "" { - var sb strings.Builder - - _, err := fmt.Fprintf(&sb, "`%s` = ?", v) - if err != nil { - logger.Error(err) - continue - } - - db = db.Where(sb.String(), c.Query(v)) - } - } - return db -} - -func QueryToFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB { - for _, v := range keys { - if c.Query(v) != "" { - var sb strings.Builder - - _, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v) - if err != nil { - logger.Error(err) - continue - } - - var sbValue strings.Builder - - _, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v)) - - if err != nil { - logger.Error(err) - continue - } - - db = db.Where(sb.String(), sbValue.String()) - } - } - return db -} - -func QueryToFussyKeysSearch(c *gin.Context, db *gorm.DB, value string, keys ...string) *gorm.DB { - if c.Query(value) == "" { - return db - } - - var condition *gorm.DB - for i, v := range keys { - sb := v + " LIKE ?" - sv := "%" + c.Query(value) + "%" - - switch i { - case 0: - condition = db.Where(db.Where(sb, sv)) - default: - condition = condition.Or(sb, sv) - } - } - - return db.Where(condition) -} - -func QueryToOrInSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB { - for _, v := range keys { - queryArray := c.QueryArray(v + "[]") - if len(queryArray) == 0 { - queryArray = c.QueryArray(v) - } - if len(queryArray) == 1 && queryArray[0] == "" { - continue - } - if len(queryArray) >= 1 { - var sb strings.Builder - - _, err := fmt.Fprintf(&sb, "`%s` IN ?", v) - if err != nil { - logger.Error(err) - continue - } - - db = db.Or(sb.String(), queryArray) - } - } - return db -} - -func QueryToOrEqualSearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB { - for _, v := range keys { - if c.Query(v) != "" { - var sb strings.Builder - - _, err := fmt.Fprintf(&sb, "`%s` = ?", v) - if err != nil { - logger.Error(err) - continue - } - - db = db.Or(sb.String(), c.Query(v)) - } - } - return db -} - -func QueryToOrFussySearch(c *gin.Context, db *gorm.DB, keys ...string) *gorm.DB { - for _, v := range keys { - if c.Query(v) != "" { - var sb strings.Builder - - _, err := fmt.Fprintf(&sb, "`%s` LIKE ?", v) - if err != nil { - logger.Error(err) - continue - } - - var sbValue strings.Builder - - _, err = fmt.Fprintf(&sbValue, "%%%s%%", c.Query(v)) - - if err != nil { - logger.Error(err) - continue - } - - db = db.Or(sb.String(), sbValue.String()) - } - } - return db -} diff --git a/internal/cosy/hook.go b/internal/cosy/hook.go deleted file mode 100644 index e409971d..00000000 --- a/internal/cosy/hook.go +++ /dev/null @@ -1,39 +0,0 @@ -package cosy - -import "gorm.io/gorm" - -func (c *Ctx[T]) GormScope(hook func(tx *gorm.DB) *gorm.DB) *Ctx[T] { - c.gormScopes = append(c.gormScopes, hook) - return c -} - -func (c *Ctx[T]) beforeExecuteHook() { - if len(c.beforeExecuteHookFunc) > 0 { - for _, v := range c.beforeExecuteHookFunc { - v(c) - } - } -} - -func (c *Ctx[T]) beforeDecodeHook() { - if len(c.beforeDecodeHookFunc) > 0 { - for _, v := range c.beforeDecodeHookFunc { - v(c) - } - } -} - -func (c *Ctx[T]) BeforeDecodeHook(hook ...func(ctx *Ctx[T])) *Ctx[T] { - c.beforeDecodeHookFunc = append(c.beforeDecodeHookFunc, hook...) - return c -} - -func (c *Ctx[T]) BeforeExecuteHook(hook ...func(ctx *Ctx[T])) *Ctx[T] { - c.beforeExecuteHookFunc = append(c.beforeExecuteHookFunc, hook...) - return c -} - -func (c *Ctx[T]) ExecutedHook(hook ...func(ctx *Ctx[T])) *Ctx[T] { - c.executedHookFunc = append(c.executedHookFunc, hook...) - return c -} diff --git a/internal/cosy/list.go b/internal/cosy/list.go deleted file mode 100644 index bbfd5143..00000000 --- a/internal/cosy/list.go +++ /dev/null @@ -1,172 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/internal/logger" - "github.com/0xJacky/Nginx-UI/model" - "github.com/0xJacky/Nginx-UI/settings" - "github.com/gin-gonic/gin" - "github.com/spf13/cast" - "gorm.io/gorm" - "net/http" -) - -func GetPagingParams(c *gin.Context) (page, offset, pageSize int) { - page = cast.ToInt(c.Query("page")) - if page == 0 { - page = 1 - } - pageSize = settings.ServerSettings.PageSize - reqPageSize := c.Query("page_size") - if reqPageSize != "" { - pageSize = cast.ToInt(reqPageSize) - } - offset = (page - 1) * pageSize - return -} - -func (c *Ctx[T]) combineStdSelectorRequest() { - StdSelectorInitID := c.ctx.QueryArray("id[]") - - if len(StdSelectorInitID) > 0 { - c.GormScope(func(tx *gorm.DB) *gorm.DB { - return tx.Where(c.itemKey+" IN ?", StdSelectorInitID) - }) - } -} - -func (c *Ctx[T]) result() (*gorm.DB, bool) { - for _, v := range c.preloads { - t := v - c.GormScope(func(tx *gorm.DB) *gorm.DB { - tx = tx.Preload(t) - return tx - }) - } - - c.beforeExecuteHook() - - var dbModel T - result := model.UseDB() - - if cast.ToBool(c.ctx.Query("trash")) { - tableName := c.table - if c.table == "" { - stmt := &gorm.Statement{DB: model.UseDB()} - err := stmt.Parse(&dbModel) - if err != nil { - logger.Error(err) - return nil, false - } - tableName = stmt.Schema.Table - } - - result = result.Unscoped().Where(tableName + ".deleted_at IS NOT NULL") - } - - result = result.Model(&dbModel) - if c.table != "" { - result = result.Table(c.table, c.tableArgs...) - } - - c.combineStdSelectorRequest() - - if len(c.gormScopes) > 0 { - result = result.Scopes(c.gormScopes...) - } - - return result, true -} - -func (c *Ctx[T]) ListAllData() (data any, ok bool) { - result, ok := c.result() - if !ok { - return nil, false - } - - result = result.Scopes(c.SortOrder()) - if c.scan == nil { - models := make([]*T, 0) - result.Find(&models) - - if c.transformer != nil { - transformed := make([]any, 0) - for k := range models { - transformed = append(transformed, c.transformer(models[k])) - } - data = transformed - } else { - data = models - } - } else { - data = c.scan(result) - } - return data, true -} - -func (c *Ctx[T]) PagingListData() (*model.DataList, bool) { - result, ok := c.result() - if !ok { - return nil, false - } - - scopesResult := result.Scopes(c.OrderAndPaginate()) - data := &model.DataList{} - if c.scan == nil { - models := make([]*T, 0) - scopesResult.Find(&models) - - if c.transformer != nil { - transformed := make([]any, 0) - for k := range models { - transformed = append(transformed, c.transformer(models[k])) - } - data.Data = transformed - } else { - data.Data = models - } - } else { - data.Data = c.scan(scopesResult) - } - - var totalRecords int64 - delete(result.Statement.Clauses, "ORDER BY") - delete(result.Statement.Clauses, "LIMIT") - result.Count(&totalRecords) - - page := cast.ToInt(c.ctx.Query("page")) - if page == 0 { - page = 1 - } - - pageSize := settings.ServerSettings.PageSize - if reqPageSize := c.ctx.Query("page_size"); reqPageSize != "" { - pageSize = cast.ToInt(reqPageSize) - } - - data.Pagination = model.Pagination{ - Total: totalRecords, - PerPage: pageSize, - CurrentPage: page, - TotalPages: model.TotalPage(totalRecords, pageSize), - } - return data, true -} - -func (c *Ctx[T]) PagingList() { - data, ok := c.PagingListData() - if ok { - c.ctx.JSON(http.StatusOK, data) - } -} - -// EmptyPagingList return empty list -func (c *Ctx[T]) EmptyPagingList() { - pageSize := settings.ServerSettings.PageSize - if reqPageSize := c.ctx.Query("page_size"); reqPageSize != "" { - pageSize = cast.ToInt(reqPageSize) - } - - data := &model.DataList{Data: make([]any, 0)} - data.Pagination.PerPage = pageSize - c.ctx.JSON(http.StatusOK, data) -} diff --git a/internal/cosy/map2struct/hook.go b/internal/cosy/map2struct/hook.go deleted file mode 100644 index 50161615..00000000 --- a/internal/cosy/map2struct/hook.go +++ /dev/null @@ -1,96 +0,0 @@ -package map2struct - -import ( - "github.com/mitchellh/mapstructure" - "github.com/shopspring/decimal" - "github.com/spf13/cast" - "gopkg.in/guregu/null.v4" - "reflect" - "time" -) - -var timeLocation *time.Location - -func init() { - timeLocation, _ = time.LoadLocation("Asia/Shanghai") -} - -func ToTimeHookFunc() mapstructure.DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}) (interface{}, error) { - if t != reflect.TypeOf(time.Time{}) { - return data, nil - } - - switch f.Kind() { - case reflect.String: - return cast.ToTimeInDefaultLocationE(data, timeLocation) - case reflect.Float64: - return time.Unix(0, int64(data.(float64))*int64(time.Millisecond)), nil - case reflect.Int64: - return time.Unix(0, data.(int64)*int64(time.Millisecond)), nil - default: - return data, nil - } - // Convert it by parsing - } -} - -func ToTimePtrHookFunc() mapstructure.DecodeHookFunc { - return func( - f reflect.Type, - t reflect.Type, - data interface{}) (interface{}, error) { - if t != reflect.TypeOf(&time.Time{}) { - return data, nil - } - - switch f.Kind() { - case reflect.String: - if data == "" { - return nil, nil - } - v, err := cast.ToTimeInDefaultLocationE(data, timeLocation) - return &v, err - case reflect.Float64: - v := time.Unix(0, int64(data.(float64))*int64(time.Millisecond)) - return &v, nil - case reflect.Int64: - v := time.Unix(0, data.(int64)*int64(time.Millisecond)) - return &v, nil - default: - return data, nil - } - // Convert it by parsing - } -} - -func ToDecimalHookFunc() mapstructure.DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - - if t == reflect.TypeOf(decimal.Decimal{}) { - if f.Kind() == reflect.Float64 { - return decimal.NewFromFloat(data.(float64)), nil - } - - if input := data.(string); input != "" { - return decimal.NewFromString(data.(string)) - } - return decimal.Decimal{}, nil - } - - return data, nil - } -} - -func ToNullableStringHookFunc() mapstructure.DecodeHookFunc { - return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) { - if t == reflect.TypeOf(null.String{}) { - return null.StringFrom(data.(string)), nil - } - - return data, nil - } -} diff --git a/internal/cosy/map2struct/map2struct.go b/internal/cosy/map2struct/map2struct.go deleted file mode 100644 index 49f4f4cd..00000000 --- a/internal/cosy/map2struct/map2struct.go +++ /dev/null @@ -1,25 +0,0 @@ -package map2struct - -import ( - "github.com/mitchellh/mapstructure" -) - -func WeakDecode(input, output interface{}) error { - config := &mapstructure.DecoderConfig{ - Metadata: nil, - Result: output, - WeaklyTypedInput: true, - DecodeHook: mapstructure.ComposeDecodeHookFunc( - ToDecimalHookFunc(), ToTimeHookFunc(), ToNullableStringHookFunc(), - ToTimePtrHookFunc(), - ), - TagName: "json", - } - - decoder, err := mapstructure.NewDecoder(config) - if err != nil { - return err - } - - return decoder.Decode(input) -} diff --git a/internal/cosy/order.go b/internal/cosy/order.go deleted file mode 100644 index 4f6b4ac1..00000000 --- a/internal/cosy/order.go +++ /dev/null @@ -1,46 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/api" - "github.com/0xJacky/Nginx-UI/model" - "gorm.io/gorm" - "net/http" -) - -func (c *Ctx[T]) UpdateOrder() { - var json struct { - TargetID int `json:"target_id"` - Direction int `json:"direction" binding:"oneof=-1 1"` - AffectedIDs []int `json:"affected_ids"` - } - - if !api.BindAndValid(c.ctx, &json) { - return - } - - affectedLen := len(json.AffectedIDs) - - db := model.UseDB() - - if c.table != "" { - db = db.Table(c.table, c.tableArgs...) - } - - // update target - err := db.Model(&c.Model).Where("id = ?", json.TargetID).Update("order_id", gorm.Expr("order_id + ?", affectedLen*(-json.Direction))).Error - - if err != nil { - api.ErrHandler(c.ctx, err) - return - } - - // update affected - err = db.Model(&c.Model).Where("id in ?", json.AffectedIDs).Update("order_id", gorm.Expr("order_id + ?", json.Direction)).Error - - if err != nil { - api.ErrHandler(c.ctx, err) - return - } - - c.ctx.JSON(http.StatusOK, json) -} diff --git a/internal/cosy/sort.go b/internal/cosy/sort.go deleted file mode 100644 index 20634427..00000000 --- a/internal/cosy/sort.go +++ /dev/null @@ -1,41 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/internal/logger" - "gorm.io/gorm" - "gorm.io/gorm/schema" - "strings" - "sync" -) - -func (c *Ctx[T]) SortOrder() func(db *gorm.DB) *gorm.DB { - return func(db *gorm.DB) *gorm.DB { - order := c.ctx.DefaultQuery("order", "desc") - if order != "desc" && order != "asc" { - order = "desc" - } - - sortBy := c.ctx.DefaultQuery("sort_by", c.itemKey) - - s, _ := schema.Parse(c.Model, &sync.Map{}, schema.NamingStrategy{}) - if _, ok := s.FieldsByDBName[sortBy]; !ok && sortBy != c.itemKey { - logger.Error("invalid order field:", sortBy) - return db - } - - var sb strings.Builder - sb.WriteString(sortBy) - sb.WriteString(" ") - sb.WriteString(order) - - return db.Order(sb.String()) - } -} - -func (c *Ctx[T]) OrderAndPaginate() func(db *gorm.DB) *gorm.DB { - return func(db *gorm.DB) *gorm.DB { - db = c.SortOrder()(db) - _, offset, pageSize := GetPagingParams(c.ctx) - return db.Offset(offset).Limit(pageSize) - } -} diff --git a/internal/cosy/update.go b/internal/cosy/update.go deleted file mode 100644 index 19e91477..00000000 --- a/internal/cosy/update.go +++ /dev/null @@ -1,101 +0,0 @@ -package cosy - -import ( - "github.com/0xJacky/Nginx-UI/internal/cosy/map2struct" - "github.com/0xJacky/Nginx-UI/model" - "github.com/gin-gonic/gin" - "gorm.io/gorm" - "gorm.io/gorm/clause" - "net/http" -) - -func (c *Ctx[T]) SetNextHandler(handler gin.HandlerFunc) *Ctx[T] { - c.nextHandler = &handler - return c -} - -func (c *Ctx[T]) Modify() { - if c.abort { - return - } - id := c.ctx.Param("id") - errs := c.validate() - - if len(errs) > 0 { - c.ctx.JSON(http.StatusNotAcceptable, gin.H{ - "message": "Requested with wrong parameters", - "errors": errs, - }) - return - } - - db := model.UseDB() - - result := db - if len(c.gormScopes) > 0 { - result = result.Scopes(c.gormScopes...) - } - - err := result.Session(&gorm.Session{}).First(&c.OriginModel, id).Error - - if err != nil { - c.AbortWithError(err) - return - } - - c.beforeDecodeHook() - if c.abort { - return - } - - var selectedFields []string - - for k := range c.Payload { - selectedFields = append(selectedFields, k) - } - - err = map2struct.WeakDecode(c.Payload, &c.Model) - - if err != nil { - errHandler(c.ctx, err) - return - } - - c.beforeExecuteHook() - if c.abort { - return - } - - if c.table != "" { - db = db.Table(c.table, c.tableArgs...) - } - err = db.Model(&c.OriginModel).Select(selectedFields).Updates(&c.Model).Error - - if err != nil { - c.AbortWithError(err) - return - } - - err = db.Preload(clause.Associations).First(&c.Model, id).Error - - if err != nil { - c.AbortWithError(err) - return - } - - if len(c.executedHookFunc) > 0 { - for _, v := range c.executedHookFunc { - v(c) - - if c.abort { - return - } - } - } - - if c.nextHandler != nil { - (*c.nextHandler)(c.ctx) - } else { - c.ctx.JSON(http.StatusOK, c.Model) - } -} diff --git a/internal/cron/cron.go b/internal/cron/cron.go index decda2e2..98721dfd 100644 --- a/internal/cron/cron.go +++ b/internal/cron/cron.go @@ -2,7 +2,7 @@ package cron import ( "github.com/0xJacky/Nginx-UI/internal/cert" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/logrotate" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" diff --git a/internal/helper/directory.go b/internal/helper/directory.go index fef5b90a..b710e83e 100644 --- a/internal/helper/directory.go +++ b/internal/helper/directory.go @@ -1,7 +1,7 @@ package helper import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "path/filepath" "strings" ) diff --git a/internal/helper/hash.go b/internal/helper/hash.go index 86959e6a..3d5a82ce 100644 --- a/internal/helper/hash.go +++ b/internal/helper/hash.go @@ -3,7 +3,7 @@ package helper import ( "crypto/sha512" "fmt" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "io" "os" ) diff --git a/internal/kernal/boot.go b/internal/kernal/boot.go index 20ea8359..a2256a82 100644 --- a/internal/kernal/boot.go +++ b/internal/kernal/boot.go @@ -8,14 +8,18 @@ import ( "github.com/0xJacky/Nginx-UI/internal/cert" "github.com/0xJacky/Nginx-UI/internal/cluster" "github.com/0xJacky/Nginx-UI/internal/cron" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/passkey" "github.com/0xJacky/Nginx-UI/internal/validation" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" "github.com/google/uuid" + "github.com/uozi-tech/cosy" + sqlite "github.com/uozi-tech/cosy-driver-sqlite" + "github.com/uozi-tech/cosy/logger" + cSettings "github.com/uozi-tech/cosy/settings" "mime" + "path" "runtime" ) @@ -23,6 +27,7 @@ func Boot() { defer recovery() async := []func(){ + settings.Init, InitJsExtensionType, InitDatabase, InitNodeSecret, @@ -70,12 +75,13 @@ func recovery() { func InitDatabase() { // Skip install - if settings.ServerSettings.SkipInstallation { + if settings.NodeSettings.SkipInstallation { skipInstall() } - if "" != settings.ServerSettings.JwtSecret { - db := model.Init() + if "" != cSettings.AppSettings.JwtSecret { + db := cosy.InitDB(sqlite.Open(path.Dir(cSettings.ConfPath), cSettings.DataBaseSettings)) + model.Use(db) query.Init(db) InitAfterDatabase() @@ -83,21 +89,22 @@ func InitDatabase() { } func InitNodeSecret() { - if "" == settings.ServerSettings.NodeSecret { - logger.Warn("NodeSecret is empty, generating...") - settings.ServerSettings.NodeSecret = uuid.New().String() + if "" == settings.NodeSettings.Secret { + logger.Info("Secret is empty, generating...") + uuidStr := uuid.New().String() + settings.NodeSettings.Secret = uuidStr err := settings.Save() if err != nil { logger.Error("Error save settings", err) } - logger.Warn("Generated NodeSecret: ", settings.ServerSettings.NodeSecret) + logger.Info("Generated Secret: ", uuidStr) } } func InitCryptoSecret() { if "" == settings.CryptoSettings.Secret { - logger.Warn("Secret is empty, generating...") + logger.Info("Secret is empty, generating...") key := make([]byte, 32) if _, err := rand.Read(key); err != nil { @@ -111,7 +118,7 @@ func InitCryptoSecret() { if err != nil { logger.Error("Error save settings", err) } - logger.Warn("Secret Generated") + logger.Info("Secret Generated") } } diff --git a/internal/kernal/register_acme_user.go b/internal/kernal/register_acme_user.go index 89b141ca..da2cadd8 100644 --- a/internal/kernal/register_acme_user.go +++ b/internal/kernal/register_acme_user.go @@ -1,7 +1,7 @@ package kernal import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/query" ) diff --git a/internal/kernal/skip_install.go b/internal/kernal/skip_install.go index 907b3298..bc146467 100644 --- a/internal/kernal/skip_install.go +++ b/internal/kernal/skip_install.go @@ -1,13 +1,14 @@ package kernal import ( - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/settings" "github.com/caarlos0/env/v11" "github.com/google/uuid" "github.com/pkg/errors" + "github.com/uozi-tech/cosy/logger" + cSettings "github.com/uozi-tech/cosy/settings" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) @@ -20,13 +21,13 @@ type predefinedUser struct { func skipInstall() { logger.Info("Skip installation mode enabled") - if settings.ServerSettings.JwtSecret == "" { - settings.ServerSettings.JwtSecret = uuid.New().String() + if cSettings.AppSettings.JwtSecret == "" { + cSettings.AppSettings.JwtSecret = uuid.New().String() } - if settings.ServerSettings.NodeSecret == "" { - settings.ServerSettings.NodeSecret = uuid.New().String() - logger.Infof("NodeSecret: %s", settings.ServerSettings.NodeSecret) + if settings.NodeSettings.Secret == "" { + settings.NodeSettings.Secret = uuid.New().String() + logger.Infof("Secret: %s", settings.NodeSettings.Secret) } err := settings.Save() @@ -37,7 +38,7 @@ func skipInstall() { func registerPredefinedUser() { // when skip installation mode is enabled, the predefined user will be created - if !settings.ServerSettings.SkipInstallation { + if !settings.NodeSettings.SkipInstallation { return } pUser := &predefinedUser{} diff --git a/internal/logrotate/logrotate.go b/internal/logrotate/logrotate.go index 3036ea8f..51dda63b 100644 --- a/internal/logrotate/logrotate.go +++ b/internal/logrotate/logrotate.go @@ -1,7 +1,7 @@ package logrotate import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/settings" "os/exec" "strings" diff --git a/internal/middleware/middleware.go b/internal/middleware/middleware.go index 1f946442..1c250dd2 100644 --- a/internal/middleware/middleware.go +++ b/internal/middleware/middleware.go @@ -3,36 +3,17 @@ package middleware import ( "encoding/base64" "github.com/0xJacky/Nginx-UI/app" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/user" "github.com/0xJacky/Nginx-UI/settings" "github.com/gin-contrib/static" "github.com/gin-gonic/gin" + "github.com/uozi-tech/cosy/logger" "io/fs" "net/http" "path" - "runtime" "strings" ) -func Recovery() gin.HandlerFunc { - return func(c *gin.Context) { - defer func() { - if err := recover(); err != nil { - buf := make([]byte, 1024) - runtime.Stack(buf, false) - logger.Errorf("%s\n%s", err, buf) - - c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{ - "message": err.(error).Error(), - }) - } - }() - - c.Next() - } -} - func AuthRequired() gin.HandlerFunc { return func(c *gin.Context) { abortWithAuthFailure := func() { @@ -43,8 +24,8 @@ func AuthRequired() gin.HandlerFunc { token := c.GetHeader("Authorization") if token == "" { - if token = c.GetHeader("X-Node-Secret"); token != "" && token == settings.ServerSettings.NodeSecret { - c.Set("NodeSecret", token) + if token = c.GetHeader("X-Node-Secret"); token != "" && token == settings.NodeSettings.Secret { + c.Set("Secret", token) c.Next() return } else { diff --git a/internal/middleware/proxy.go b/internal/middleware/proxy.go index ef9914a6..2fd9c1d9 100644 --- a/internal/middleware/proxy.go +++ b/internal/middleware/proxy.go @@ -1,7 +1,7 @@ package middleware import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/internal/transport" "github.com/0xJacky/Nginx-UI/query" "github.com/gin-gonic/gin" diff --git a/internal/middleware/proxy_ws.go b/internal/middleware/proxy_ws.go index 24b55d25..0dfc14b3 100644 --- a/internal/middleware/proxy_ws.go +++ b/internal/middleware/proxy_ws.go @@ -1,7 +1,7 @@ package middleware import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/query" "github.com/gin-gonic/gin" "github.com/pretty66/websocketproxy" diff --git a/internal/nginx/config_args.go b/internal/nginx/config_args.go index e6f71b31..bb7d15bb 100644 --- a/internal/nginx/config_args.go +++ b/internal/nginx/config_args.go @@ -2,7 +2,7 @@ package nginx import ( "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/settings" "os/exec" "path/filepath" diff --git a/internal/passkey/webauthn.go b/internal/passkey/webauthn.go index cb47294c..e71d93a8 100644 --- a/internal/passkey/webauthn.go +++ b/internal/passkey/webauthn.go @@ -1,7 +1,7 @@ package passkey import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/0xJacky/Nginx-UI/settings" "github.com/go-webauthn/webauthn/protocol" "github.com/go-webauthn/webauthn/webauthn" @@ -10,7 +10,7 @@ import ( var instance *webauthn.WebAuthn func Init() { - options := &settings.WebAuthnSettings + options := settings.WebAuthnSettings if !Enabled() { logger.Debug("WebAuthn settings are not configured") @@ -34,7 +34,7 @@ func Init() { } func Enabled() bool { - options := &settings.WebAuthnSettings + options := settings.WebAuthnSettings if options.RPDisplayName == "" || options.RPID == "" || len(options.RPOrigins) == 0 { return false } diff --git a/internal/pty/pipeline.go b/internal/pty/pipeline.go index 80f821a7..8a9526ae 100644 --- a/internal/pty/pipeline.go +++ b/internal/pty/pipeline.go @@ -2,11 +2,11 @@ package pty import ( "encoding/json" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/settings" "github.com/creack/pty" "github.com/gorilla/websocket" "github.com/pkg/errors" + "github.com/uozi-tech/cosy/logger" "os" "os/exec" "time" @@ -27,7 +27,7 @@ type Message struct { const bufferSize = 2048 func NewPipeLine(conn *websocket.Conn) (p *Pipeline, err error) { - c := exec.Command(settings.ServerSettings.StartCmd) + c := exec.Command(settings.TerminalSettings.StartCmd) ptmx, err := pty.StartWithSize(c, &pty.Winsize{Cols: 90, Rows: 60}) if err != nil { diff --git a/internal/template/template.go b/internal/template/template.go index eeba0471..1c8acdf5 100644 --- a/internal/template/template.go +++ b/internal/template/template.go @@ -3,7 +3,6 @@ package template import ( "bufio" "bytes" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" "github.com/0xJacky/Nginx-UI/settings" templ "github.com/0xJacky/Nginx-UI/template" @@ -11,6 +10,8 @@ import ( "github.com/gin-gonic/gin" "github.com/pkg/errors" "github.com/tufanbarisyildirim/gonginx/parser" + "github.com/uozi-tech/cosy/logger" + cSettings "github.com/uozi-tech/cosy/settings" "io" "io/fs" "path/filepath" @@ -115,8 +116,8 @@ func ParseTemplate(path, name string, bindData map[string]Variable) (c ConfigDet } data := gin.H{ - "HTTPPORT": settings.ServerSettings.HttpPort, - "HTTP01PORT": settings.ServerSettings.HTTPChallengePort, + "HTTPPORT": cSettings.ServerSettings.Port, + "HTTP01PORT": settings.CertSettings.HTTPChallengePort, } for k, v := range bindData { diff --git a/internal/transport/transport.go b/internal/transport/transport.go index cb499b32..7abcc38f 100644 --- a/internal/transport/transport.go +++ b/internal/transport/transport.go @@ -11,7 +11,7 @@ import ( func NewTransport(options ...func(transport *http.Transport) error) (t *http.Transport, err error) { t = &http.Transport{ Proxy: http.ProxyFromEnvironment, - TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.ServerSettings.InsecureSkipVerify}, + TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.HTTPSettings.InsecureSkipVerify}, } for _, option := range options { diff --git a/internal/upgrader/upgrade.go b/internal/upgrader/upgrade.go index cad1a2ae..6ce42e73 100644 --- a/internal/upgrader/upgrade.go +++ b/internal/upgrader/upgrade.go @@ -5,11 +5,11 @@ import ( "fmt" _github "github.com/0xJacky/Nginx-UI/.github" "github.com/0xJacky/Nginx-UI/internal/helper" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/settings" "github.com/jpillora/overseer" "github.com/minio/selfupdate" "github.com/pkg/errors" + "github.com/uozi-tech/cosy/logger" "io" "net/http" "net/url" @@ -138,8 +138,9 @@ func (u *Upgrader) DownloadLatestRelease(progressChan chan float64) (tarName str return } - if settings.ServerSettings.GithubProxy != "" { - digest.BrowserDownloadUrl, err = url.JoinPath(settings.ServerSettings.GithubProxy, digest.BrowserDownloadUrl) + githubProxy := settings.HTTPSettings.GithubProxy + if githubProxy != "" { + digest.BrowserDownloadUrl, err = url.JoinPath(githubProxy, digest.BrowserDownloadUrl) if err != nil { err = errors.Wrap(err, "service.DownloadLatestRelease url.JoinPath error") return @@ -156,8 +157,8 @@ func (u *Upgrader) DownloadLatestRelease(progressChan chan float64) (tarName str dir := filepath.Dir(u.ExPath) - if settings.ServerSettings.GithubProxy != "" { - downloadUrl, err = url.JoinPath(settings.ServerSettings.GithubProxy, downloadUrl) + if githubProxy != "" { + downloadUrl, err = url.JoinPath(githubProxy, downloadUrl) if err != nil { err = errors.Wrap(err, "service.DownloadLatestRelease url.JoinPath error") return diff --git a/internal/user/user.go b/internal/user/user.go index be26be7e..10581ab6 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -1,12 +1,12 @@ package user import ( - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/query" - "github.com/0xJacky/Nginx-UI/settings" "github.com/golang-jwt/jwt/v4" "github.com/pkg/errors" + "github.com/uozi-tech/cosy/logger" + cSettings "github.com/uozi-tech/cosy/settings" "strings" "time" ) @@ -68,7 +68,7 @@ func GenerateJWT(user *model.User) (string, error) { } unsignedToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - signedToken, err := unsignedToken.SignedString([]byte(settings.ServerSettings.JwtSecret)) + signedToken, err := unsignedToken.SignedString([]byte(cSettings.AppSettings.JwtSecret)) if err != nil { return "", err } @@ -96,7 +96,7 @@ func ValidateJWT(token string) (claims *JWTClaims, err error) { token, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) { - return []byte(settings.ServerSettings.JwtSecret), nil + return []byte(cSettings.AppSettings.JwtSecret), nil }, ) if err != nil { diff --git a/internal/validation/validation.go b/internal/validation/validation.go index 07b60ac2..769bd60e 100644 --- a/internal/validation/validation.go +++ b/internal/validation/validation.go @@ -1,7 +1,7 @@ package validation import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "github.com/gin-gonic/gin/binding" val "github.com/go-playground/validator/v10" ) diff --git a/main.go b/main.go index bff525c5..d33be71a 100644 --- a/main.go +++ b/main.go @@ -4,31 +4,34 @@ import ( "flag" "fmt" "github.com/0xJacky/Nginx-UI/internal/kernal" - "github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/nginx" + "github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/router" "github.com/0xJacky/Nginx-UI/settings" - "github.com/gin-gonic/gin" "github.com/jpillora/overseer" - "net/http" + "github.com/uozi-tech/cosy" + "github.com/uozi-tech/cosy/logger" + cSettings "github.com/uozi-tech/cosy/settings" "time" ) -func Program(state overseer.State) { - defer logger.Sync() +func Program(confPath string) func(state overseer.State) { + return func(state overseer.State) { + defer logger.Sync() - logger.Infof("Nginx configuration directory: %s", nginx.GetConfPath()) + cosy.RegisterModels(model.GenerateAllModel()...) - kernal.Boot() + cosy.RegisterAsyncFunc(kernal.Boot, router.InitRouter) - if state.Listener != nil { - err := http.Serve(state.Listener, router.InitRouter()) - if err != nil { - logger.Error(err) + if state.Listener != nil { + cosy.SetListener(state.Listener) + + cosy.Boot(confPath) + + logger.Infof("Nginx configuration directory: %s", nginx.GetConfPath()) } + logger.Info("Server exited") } - - logger.Info("Server exited") } func main() { @@ -36,13 +39,12 @@ func main() { flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file") flag.Parse() - settings.Init(confPath) - - gin.SetMode(settings.ServerSettings.RunMode) + settings.Migrate(confPath) + cSettings.Init(confPath) overseer.Run(overseer.Config{ - Program: Program, - Address: fmt.Sprintf("%s:%s", settings.ServerSettings.HttpHost, settings.ServerSettings.HttpPort), + Program: Program(confPath), + Address: fmt.Sprintf("%s:%d", cSettings.ServerSettings.Host, cSettings.ServerSettings.Port), TerminateTimeout: 5 * time.Second, }) } diff --git a/model/config_backup.go b/model/config_backup.go index 7e76ff90..3192a0eb 100644 --- a/model/config_backup.go +++ b/model/config_backup.go @@ -1,7 +1,7 @@ package model import ( - "github.com/0xJacky/Nginx-UI/internal/logger" + "github.com/uozi-tech/cosy/logger" "os" "path/filepath" ) diff --git a/model/model.go b/model/model.go index fd601e1e..bf5392e6 100644 --- a/model/model.go +++ b/model/model.go @@ -1,15 +1,8 @@ package model import ( - "fmt" - "github.com/0xJacky/Nginx-UI/internal/logger" - "github.com/0xJacky/Nginx-UI/settings" - "github.com/gin-gonic/gin" - "gorm.io/driver/sqlite" "gorm.io/gen" "gorm.io/gorm" - gormlogger "gorm.io/gorm/logger" - "path" "time" ) @@ -38,47 +31,18 @@ func GenerateAllModel() []any { BanIP{}, Config{}, Passkey{}, + SiteCategory{}, } } -func logMode() gormlogger.Interface { - switch settings.ServerSettings.RunMode { - case gin.ReleaseMode: - return gormlogger.Default.LogMode(gormlogger.Warn) - default: - fallthrough - case gin.DebugMode: - return gormlogger.Default.LogMode(gormlogger.Info) - } +func Use(tx *gorm.DB) { + db = tx } func UseDB() *gorm.DB { return db } -func Init() *gorm.DB { - dbPath := path.Join(path.Dir(settings.ConfPath), fmt.Sprintf("%s.db", settings.ServerSettings.Database)) - - var err error - db, err = gorm.Open(sqlite.Open(dbPath), &gorm.Config{ - Logger: logMode(), - PrepareStmt: true, - DisableForeignKeyConstraintWhenMigrating: true, - }) - - if err != nil { - logger.Fatal(err.Error()) - } - - // Migrate the schema - err = db.AutoMigrate(GenerateAllModel()...) - if err != nil { - logger.Fatal(err.Error()) - } - - return db -} - type Pagination struct { Total int64 `json:"total"` PerPage int `json:"per_page"` diff --git a/model/site_category.go b/model/site_category.go new file mode 100644 index 00000000..036b4638 --- /dev/null +++ b/model/site_category.go @@ -0,0 +1,7 @@ +package model + +type SiteCategory struct { + Model + Name string `json:"name"` + SyncNodeIds []int `json:"sync_node_ids" gorm:"serializer:json"` +} diff --git a/router/routers.go b/router/routers.go index 32bb1742..5f1111e4 100644 --- a/router/routers.go +++ b/router/routers.go @@ -19,14 +19,13 @@ import ( "github.com/0xJacky/Nginx-UI/internal/middleware" "github.com/gin-contrib/static" "github.com/gin-gonic/gin" + "github.com/uozi-tech/cosy" "net/http" ) -func InitRouter() *gin.Engine { - r := gin.New() +func InitRouter() { + r := cosy.GetEngine() r.Use( - gin.Logger(), - middleware.Recovery(), middleware.CacheJs(), middleware.IPWhiteList(), static.Serve("/", middleware.MustFs("")), @@ -78,6 +77,4 @@ func InitRouter() *gin.Engine { system.InitWebSocketRouter(w) } } - - return r } diff --git a/settings/app.testing.ini b/settings/app.testing.ini new file mode 100644 index 00000000..76d3b1c4 --- /dev/null +++ b/settings/app.testing.ini @@ -0,0 +1,82 @@ +[app] +PageSize = 20 +JwtSecret = newSecret + +[server] +Host = 0.0.0.0 +Port = 9000 +RunMode = debug + +[database] +Host = +Port = 0 +User = +Password = +Name = database +TablePrefix = + +[auth] +IPWhiteList = 127.0.0.1 +BanThresholdMinutes = 10 +MaxAttempts = 10 + +[casdoor] +Endpoint = http://127.0.0.1:8001 +ClientId = 1234567890qwertyuiop +ClientSecret = 1234567890qwertyuiop1234567890qwertyuiop +CertificatePath = ./casdoor.pub +Organization = built-in +Application = nginx-ui-dev +RedirectUri = + +[cert] +Email = test +CADir = /test +CertRenewalInterval = 7 +RecursiveNameservers = 8.8.8.8,1.1.1.1 +HTTPChallengePort = 9181 + +[cluster] +Node = http://10.0.0.1:9000?name=test&node_secret=asdfghjklqwertyuiopzxcvbnm&enabled=true + +[crypto] +Secret = 12345678901234567890 + +[http] +GithubProxy = https://mirror.ghproxy.com/ +InsecureSkipVerify = true + +[logrotate] +Enabled = true +CMD = logrotate /etc/logrotate.d/nginx +Interval = 1440 + +[nginx] +AccessLogPath = +ErrorLogPath = +LogDirWhiteList = /var/log/nginx +ConfigDir = +PIDPath = +TestConfigCmd = +ReloadCmd = +RestartCmd = + +[node] +Name = Local +Secret = +SkipInstallation = false +Demo = false + +[openai] +BaseUrl = +Token = +Proxy = +Model = gpt-4o + +[terminal] +StartCmd = bash + +[webauthn] +RPDisplayName = Nginx UI +RPID = localhost +RPOrigins = http://localhost:3002,http://127.0.0.1:3002 diff --git a/settings/auth.go b/settings/auth.go index cf75c7b4..8c2a717c 100644 --- a/settings/auth.go +++ b/settings/auth.go @@ -6,7 +6,7 @@ type Auth struct { MaxAttempts int `json:"max_attempts" binding:"min=1"` } -var AuthSettings = Auth{ +var AuthSettings = &Auth{ BanThresholdMinutes: 10, MaxAttempts: 10, } diff --git a/settings/casdoor.go b/settings/casdoor.go index f9f58406..4dc1054a 100644 --- a/settings/casdoor.go +++ b/settings/casdoor.go @@ -10,7 +10,7 @@ type Casdoor struct { RedirectUri string `json:"redirect_uri" protected:"true"` } -var CasdoorSettings = Casdoor{ +var CasdoorSettings = &Casdoor{ Endpoint: "", ClientId: "", ClientSecret: "", diff --git a/settings/cert.go b/settings/cert.go new file mode 100644 index 00000000..19eba1bf --- /dev/null +++ b/settings/cert.go @@ -0,0 +1,36 @@ +package settings + +import "github.com/go-acme/lego/v4/lego" + +type Cert struct { + Email string `json:"email" protected:"true"` + CADir string `json:"ca_dir" binding:"omitempty,url"` + RenewalInterval int `json:"cert_renewal_interval" binding:"min=7,max=21"` + RecursiveNameservers []string `json:"recursive_nameservers" binding:"omitempty,dive,hostname_port"` + HTTPChallengePort string `json:"http_challenge_port"` +} + +var CertSettings = &Cert{ + Email: "", + CADir: "", + RenewalInterval: 7, + RecursiveNameservers: []string{}, + HTTPChallengePort: "9180", +} + +func (s *Cert) GetCADir() string { + if s.CADir != "" { + return s.CADir + } + return lego.LEDirectoryProduction +} + +func (s *Cert) GetCertRenewalInterval() int { + if s.RenewalInterval < 7 { + return 7 + } + if s.RenewalInterval > 21 { + return 21 + } + return s.RenewalInterval +} diff --git a/settings/cluster.go b/settings/cluster.go index d86ec370..dc7e603e 100644 --- a/settings/cluster.go +++ b/settings/cluster.go @@ -1,19 +1,21 @@ package settings +import "github.com/uozi-tech/cosy/settings" + type Cluster struct { Node []string `ini:",,allowshadow"` } -var ClusterSettings = Cluster{ +var ClusterSettings = &Cluster{ Node: []string{}, } func ReloadCluster() (err error) { - err = load() + err = settings.Reload() if err != nil { return err } - return mapTo("cluster", &ClusterSettings) + return settings.MapTo("cluster", &ClusterSettings) } diff --git a/settings/cluster_test.go b/settings/cluster_test.go deleted file mode 100644 index 235b47b6..00000000 --- a/settings/cluster_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package settings - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestCluster(t *testing.T) { - Init("../app.example.ini") - - assert.Equal(t, []string{ - "http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true", - "http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=true", - "http://10.0.0.3?name=node3&node_secret=my-node-secret&enabled=true", - }, ClusterSettings.Node) -} diff --git a/settings/crypto.go b/settings/crypto.go index 57d5e0c6..a4c9d093 100644 --- a/settings/crypto.go +++ b/settings/crypto.go @@ -6,7 +6,7 @@ type Crypto struct { Secret string } -var CryptoSettings = Crypto{} +var CryptoSettings = &Crypto{} func (c *Crypto) GetSecretMd5() []byte { k := md5.Sum([]byte(c.Secret)) diff --git a/settings/crypto_test.go b/settings/crypto_test.go index db10bae5..945879cb 100644 --- a/settings/crypto_test.go +++ b/settings/crypto_test.go @@ -9,7 +9,7 @@ import ( ) func TestGetSecretMd5_WithNonEmptySecret_ReturnsExpectedMd5Hash(t *testing.T) { - // Setup + // Init CryptoSettings.Secret = "testSecret" expectedMd5 := md5.Sum([]byte("testSecret")) expectedMd5String := hex.EncodeToString(expectedMd5[:]) @@ -23,7 +23,7 @@ func TestGetSecretMd5_WithNonEmptySecret_ReturnsExpectedMd5Hash(t *testing.T) { } func TestGetSecretMd5_WithEmptySecret_ReturnsMd5OfEmptyString(t *testing.T) { - // Setup + // Init CryptoSettings.Secret = "" expectedMd5 := md5.Sum([]byte("")) expectedMd5String := hex.EncodeToString(expectedMd5[:]) @@ -37,7 +37,7 @@ func TestGetSecretMd5_WithEmptySecret_ReturnsMd5OfEmptyString(t *testing.T) { } func TestGetSecretMd5_WithDifferentSecrets_ReturnsDifferentMd5Hashes(t *testing.T) { - // Setup + // Init CryptoSettings.Secret = "secret1" firstMd5 := CryptoSettings.GetSecretMd5() CryptoSettings.Secret = "secret2" diff --git a/settings/http.go b/settings/http.go new file mode 100644 index 00000000..022b6f30 --- /dev/null +++ b/settings/http.go @@ -0,0 +1,11 @@ +package settings + +type HTTP struct { + GithubProxy string `json:"github_proxy" binding:"omitempty,url"` + InsecureSkipVerify bool `json:"insecure_skip_verify" protected:"true"` +} + +var HTTPSettings = &HTTP{ + GithubProxy: "", + InsecureSkipVerify: false, +} diff --git a/settings/logrotate.go b/settings/logrotate.go index 4390b154..4f3d5a1a 100644 --- a/settings/logrotate.go +++ b/settings/logrotate.go @@ -6,7 +6,7 @@ type Logrotate struct { Interval int `json:"interval"` } -var LogrotateSettings = Logrotate{ +var LogrotateSettings = &Logrotate{ Enabled: false, CMD: "logrotate /etc/logrotate.d/nginx", Interval: 1440, // 24 hours diff --git a/settings/nginx.go b/settings/nginx.go index 9be09184..51a1d923 100644 --- a/settings/nginx.go +++ b/settings/nginx.go @@ -11,7 +11,7 @@ type Nginx struct { RestartCmd string `json:"restart_cmd" protected:"true"` } -var NginxSettings = Nginx{ +var NginxSettings = &Nginx{ AccessLogPath: "", ErrorLogPath: "", } diff --git a/settings/node.go b/settings/node.go new file mode 100644 index 00000000..a0890c82 --- /dev/null +++ b/settings/node.go @@ -0,0 +1,15 @@ +package settings + +type Node struct { + Name string `json:"name" binding:"omitempty,safety_text"` + Secret string `json:"secret" protected:"true"` + SkipInstallation bool `json:"skip_installation" protected:"true"` + Demo bool `json:"demo" protected:"true"` +} + +var NodeSettings = &Node{ + Name: "", + Secret: "", + SkipInstallation: false, + Demo: false, +} diff --git a/settings/openai.go b/settings/openai.go index 66eaa47f..c5a119a9 100644 --- a/settings/openai.go +++ b/settings/openai.go @@ -7,4 +7,4 @@ type OpenAI struct { Model string `json:"model" binding:"omitempty,safety_text"` } -var OpenAISettings = OpenAI{} +var OpenAISettings = &OpenAI{} diff --git a/settings/server.go b/settings/server.go deleted file mode 100644 index 7f2d303a..00000000 --- a/settings/server.go +++ /dev/null @@ -1,63 +0,0 @@ -package settings - -import ( - "github.com/go-acme/lego/v4/lego" -) - -type Server struct { - HttpHost string `json:"http_host" protected:"true"` - HttpPort string `json:"http_port" protected:"true"` - RunMode string `json:"run_mode" protected:"true"` - JwtSecret string `json:"jwt_secret" protected:"true"` - NodeSecret string `json:"node_secret" protected:"true"` - HTTPChallengePort string `json:"http_challenge_port"` - Email string `json:"email" protected:"true"` - Database string `json:"database" protected:"true"` - StartCmd string `json:"start_cmd" protected:"true"` - CADir string `json:"ca_dir" binding:"omitempty,url"` - Demo bool `json:"demo" protected:"true"` - PageSize int `json:"page_size" protected:"true"` - GithubProxy string `json:"github_proxy" binding:"omitempty,url"` - CertRenewalInterval int `json:"cert_renewal_interval" binding:"min=7,max=21"` - RecursiveNameservers []string `json:"recursive_nameservers" binding:"omitempty,dive,hostname_port"` - SkipInstallation bool `json:"skip_installation" protected:"true"` - InsecureSkipVerify bool `json:"insecure_skip_verify" protected:"true"` - Name string `json:"name" binding:"omitempty,safety_text"` -} - -func (s *Server) GetCADir() string { - if s.Demo { - return lego.LEDirectoryStaging - } - - if s.CADir != "" { - return s.CADir - } - - return lego.LEDirectoryProduction -} - -func (s *Server) GetCertRenewalInterval() int { - if s.CertRenewalInterval < 7 { - return 7 - } - if s.CertRenewalInterval > 21 { - return 21 - } - return s.CertRenewalInterval -} - -var ServerSettings = Server{ - HttpHost: "0.0.0.0", - HttpPort: "9000", - RunMode: "debug", - HTTPChallengePort: "9180", - Database: "database", - StartCmd: "login", - Demo: false, - PageSize: 10, - CADir: "", - GithubProxy: "", - CertRenewalInterval: 7, - RecursiveNameservers: make([]string, 0), -} diff --git a/settings/server_v1.go b/settings/server_v1.go new file mode 100644 index 00000000..3f1118b7 --- /dev/null +++ b/settings/server_v1.go @@ -0,0 +1,227 @@ +package settings + +import ( + "github.com/elliotchance/orderedmap/v2" + "github.com/spf13/cast" + "github.com/uozi-tech/cosy/logger" + "github.com/uozi-tech/cosy/settings" + "gopkg.in/ini.v1" + "os" + "reflect" +) + +// Note: This section will be deprecated in the future version. + +type serverV1 struct { + HttpHost string `json:"http_host" protected:"true"` + HttpPort string `json:"http_port" protected:"true"` + RunMode string `json:"run_mode" protected:"true"` + JwtSecret string `json:"jwt_secret" protected:"true"` + NodeSecret string `json:"node_secret" protected:"true"` + HTTPChallengePort string `json:"http_challenge_port"` + Email string `json:"email" protected:"true"` + Database string `json:"database" protected:"true"` + StartCmd string `json:"start_cmd" protected:"true"` + CADir string `json:"ca_dir"` + Demo bool `json:"demo" protected:"true"` + PageSize int `json:"page_size" protected:"true"` + GithubProxy string `json:"github_proxy"` + CertRenewalInterval int `json:"cert_renewal_interval"` + RecursiveNameservers []string `json:"recursive_nameservers"` + SkipInstallation bool `json:"skip_installation" protected:"true"` + InsecureSkipVerify bool `json:"insecure_skip_verify" protected:"true"` + Name string `json:"name"` +} + +type settingsV2 struct { + // Cosy + App settings.App + Server settings.Server + DataBase settings.DataBase + // Nginx UI + Auth Auth + Casdoor Casdoor + Cert Cert + Cluster Cluster + Crypto Crypto + Http HTTP + Logrotate Logrotate + Nginx Nginx + Node Node + OpenAI OpenAI + Terminal Terminal + WebAuthn WebAuthn +} + +func (v1 *serverV1) migrateToV2() (v2 *settingsV2) { + v2 = &settingsV2{} + v2.Server.Host = v1.HttpHost + v2.Server.Port = cast.ToUint(v1.HttpPort) + v2.Server.RunMode = v1.RunMode + v2.App.JwtSecret = v1.JwtSecret + v2.App.PageSize = v1.PageSize + v2.Node.Secret = v1.NodeSecret + v2.Cert.HTTPChallengePort = v1.HTTPChallengePort + v2.Cert.Email = v1.Email + v2.DataBase.Name = v1.Database + v2.Terminal.StartCmd = v1.StartCmd + v2.Cert.CADir = v1.CADir + v2.Node.Demo = v1.Demo + v2.Http.GithubProxy = v1.GithubProxy + v2.Cert.RenewalInterval = v1.CertRenewalInterval + v2.Cert.RecursiveNameservers = v1.RecursiveNameservers + v2.Node.SkipInstallation = v1.SkipInstallation + v2.Http.InsecureSkipVerify = v1.InsecureSkipVerify + v2.Node.Name = v1.Name + + return +} + +func isZeroValue(v reflect.Value) bool { + zeroValue := reflect.Zero(v.Type()).Interface() + return reflect.DeepEqual(v.Interface(), zeroValue) +} + +func mergeStructs(src, dst interface{}) { + dstVal := reflect.ValueOf(dst).Elem() + srcVal := reflect.ValueOf(src).Elem() + + for i := 0; i < dstVal.NumField(); i++ { + dstField := dstVal.Field(i) + srcField := srcVal.Field(i) + if isZeroValue(dstField) { + dstField.Set(srcField) + } + } + return +} + +func Migrate(confPath string) { + logger.Init("debug") + Conf, err := ini.LoadSources(ini.LoadOptions{ + Loose: true, + AllowShadows: true, + }, confPath) + if err != nil { + logger.Fatalf("setting.init, fail to parse 'app.ini': %v", err) + } + + var v1 = &serverV1{} + err = Conf.Section("server").MapTo(v1) + if err != nil { + logger.Error(err) + return + } + + // If settings is v1, jwt_secret is not empty. + if v1.JwtSecret == "" { + return + } + + // Cosy + app := &settings.App{} + server := &settings.Server{} + database := &settings.DataBase{} + // Nginx UI + auth := &Auth{} + casdoor := &Casdoor{} + cert := &Cert{} + cluster := &Cluster{} + crypto := &Crypto{} + http := &HTTP{} + logrotate := &Logrotate{} + nginx := &Nginx{} + node := &Node{} + openai := &OpenAI{} + terminal := &Terminal{} + webauthn := &WebAuthn{} + + var migrated = orderedmap.NewOrderedMap[string, any]() + migrated.Set("app", app) + migrated.Set("server", server) + migrated.Set("database", database) + migrated.Set("auth", auth) + migrated.Set("casdoor", casdoor) + migrated.Set("cert", cert) + migrated.Set("cluster", cluster) + migrated.Set("crypto", crypto) + migrated.Set("http", http) + migrated.Set("logrotate", logrotate) + migrated.Set("nginx", nginx) + migrated.Set("node", node) + migrated.Set("openai", openai) + migrated.Set("terminal", terminal) + migrated.Set("webauthn", webauthn) + + for name, ptr := range migrated.Iterator() { + err = Conf.Section(name).MapTo(ptr) + if err != nil { + logger.Error("Migrate.MapTo %s err: %v", name, err) + } + } + + v2 := v1.migrateToV2() + + mergeStructs(&v2.App, app) + mergeStructs(&v2.Server, server) + mergeStructs(&v2.DataBase, database) + mergeStructs(&v2.Auth, auth) + mergeStructs(&v2.Casdoor, casdoor) + mergeStructs(&v2.Cert, cert) + mergeStructs(&v2.Cluster, cluster) + mergeStructs(&v2.Crypto, crypto) + mergeStructs(&v2.Http, http) + mergeStructs(&v2.Logrotate, logrotate) + mergeStructs(&v2.Nginx, nginx) + mergeStructs(&v2.Node, node) + mergeStructs(&v2.OpenAI, openai) + mergeStructs(&v2.Terminal, terminal) + mergeStructs(&v2.WebAuthn, webauthn) + + Conf = ini.Empty() + + for section, ptr := range migrated.Iterator() { + err = Conf.Section(section).ReflectFrom(ptr) + if err != nil { + logger.Fatalf("Migrate.ReflectFrom %s err: %v", section, err) + } + } + + err = Conf.SaveTo(confPath) + if err != nil { + logger.Fatalf("Fail to save the migrated settings: %v", err) + return + } + + migrateEnv() +} + +func migrateEnv() { + deprecated := orderedmap.NewOrderedMap[string, string]() + deprecated.Set("SERVER_HTTP_HOST", "SERVER_HOST") + deprecated.Set("SERVER_HTTP_PORT", "SERVER_PORT") + deprecated.Set("SERVER_JWT_SECRET", "APP_JWT_SECRET") + deprecated.Set("SERVER_NODE_SECRET", "NODE_SECRET") + deprecated.Set("SERVER_HTTP_CHALLENGE_PORT", "CERT_HTTP_CHALLENGE_PORT") + deprecated.Set("SERVER_EMAIL", "CERT_EMAIL") + deprecated.Set("SERVER_DATABASE", "DATABASE_NAME") + deprecated.Set("SERVER_START_CMD", "TERMINAL_START_CMD") + deprecated.Set("SERVER_CA_DIR", "CERT_CA_DIR") + deprecated.Set("SERVER_DEMO", "NODE_DEMO") + deprecated.Set("SERVER_PAGE_SIZE", "APP_PAGE_SIZE") + deprecated.Set("SERVER_GITHUB_PROXY", "HTTP_GITHUB_PROXY") + deprecated.Set("SERVER_CERT_RENEWAL_INTERVAL", "CERT_RENEWAL_INTERVAL") + deprecated.Set("SERVER_RECURSIVE_NAMESERVERS", "CERT_RECURSIVE_NAMESERVERS") + deprecated.Set("SERVER_SKIP_INSTALLATION", "NODE_SKIP_INSTALLATION") + deprecated.Set("SERVER_NAME", "NODE_NAME") + + for d, n := range deprecated.Iterator() { + oldValue := os.Getenv(EnvPrefix + d) + if oldValue != "" { + _ = os.Setenv(EnvPrefix+n, oldValue) + logger.Warnf("The environment variable %s is deprecated and has been automatically migrated to %s. "+ + "Please update your environment variables as automatic migration may be removed in the future.", + EnvPrefix+d, EnvPrefix+n) + } + } +} diff --git a/settings/server_v1_test.go b/settings/server_v1_test.go new file mode 100644 index 00000000..ce29093e --- /dev/null +++ b/settings/server_v1_test.go @@ -0,0 +1,125 @@ +package settings + +import ( + "github.com/stretchr/testify/assert" + "github.com/uozi-tech/cosy/logger" + "os" + "testing" +) + +func TestDeprecatedEnvMigration(t *testing.T) { + logger.Init("debug") + // Deprecated + _ = os.Setenv("NGINX_UI_SERVER_HTTP_HOST", "127.0.0.1") + _ = os.Setenv("NGINX_UI_SERVER_HTTP_PORT", "8080") + // _ = os.Setenv("NGINX_UI_SERVER_RUN_MODE", "testing") + _ = os.Setenv("NGINX_UI_SERVER_JWT_SECRET", "newSecret123") + _ = os.Setenv("NGINX_UI_SERVER_NODE_SECRET", "newSercet123") + _ = os.Setenv("NGINX_UI_SERVER_HTTP_CHALLENGE_PORT", "9181") + _ = os.Setenv("NGINX_UI_SERVER_EMAIL", "test") + _ = os.Setenv("NGINX_UI_SERVER_DATABASE", "testDB") + _ = os.Setenv("NGINX_UI_SERVER_START_CMD", "start") + _ = os.Setenv("NGINX_UI_SERVER_CA_DIR", "/test/ca") + _ = os.Setenv("NGINX_UI_SERVER_DEMO", "true") + _ = os.Setenv("NGINX_UI_SERVER_PAGE_SIZE", "20") + _ = os.Setenv("NGINX_UI_SERVER_GITHUB_PROXY", "http://proxy.example.com") + _ = os.Setenv("NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL", "14") + _ = os.Setenv("NGINX_UI_SERVER_RECURSIVE_NAMESERVERS", "8.8.8.8,1.1.1.1") + _ = os.Setenv("NGINX_UI_SERVER_SKIP_INSTALLATION", "true") + _ = os.Setenv("NGINX_UI_SERVER_NAME", "test") + + migrateEnv() + + assert.Equal(t, "127.0.0.1", os.Getenv("NGINX_UI_SERVER_HOST")) + assert.Equal(t, "8080", os.Getenv("NGINX_UI_SERVER_PORT")) + // assert.Equal(t, "testing", os.Getenv("NGINX_UI_SERVER_RUN_MODE")) + assert.Equal(t, "newSecret123", os.Getenv("NGINX_UI_APP_JWT_SECRET")) + assert.Equal(t, "newSercet123", os.Getenv("NGINX_UI_NODE_SECRET")) + assert.Equal(t, "9181", os.Getenv("NGINX_UI_CERT_HTTP_CHALLENGE_PORT")) + assert.Equal(t, "test", os.Getenv("NGINX_UI_CERT_EMAIL")) + assert.Equal(t, "testDB", os.Getenv("NGINX_UI_DATABASE_NAME")) + assert.Equal(t, "start", os.Getenv("NGINX_UI_TERMINAL_START_CMD")) + assert.Equal(t, "/test/ca", os.Getenv("NGINX_UI_CERT_CA_DIR")) + assert.Equal(t, "true", os.Getenv("NGINX_UI_NODE_DEMO")) + assert.Equal(t, "20", os.Getenv("NGINX_UI_APP_PAGE_SIZE")) + assert.Equal(t, "http://proxy.example.com", os.Getenv("NGINX_UI_HTTP_GITHUB_PROXY")) + assert.Equal(t, "14", os.Getenv("NGINX_UI_CERT_RENEWAL_INTERVAL")) + assert.Equal(t, "8.8.8.8,1.1.1.1", os.Getenv("NGINX_UI_CERT_RECURSIVE_NAMESERVERS")) + assert.Equal(t, "true", os.Getenv("NGINX_UI_NODE_SKIP_INSTALLATION")) + assert.Equal(t, "test", os.Getenv("NGINX_UI_NODE_NAME")) +} + +func TestMigration(t *testing.T) { + const confName = "app.testing.ini" + confText := `[server] +HttpPort = 9000 +RunMode = debug +JwtSecret = newSecret +Email = test +HTTPChallengePort = 9181 +StartCmd = bash +Database = database +CADir = /test +GithubProxy = https://mirror.ghproxy.com/ +Secret = newSecret +Demo = false +PageSize = 20 +HttpHost = 0.0.0.0 +RenewalInterval = 7 +RecursiveNameservers = 8.8.8.8,1.1.1.1 +SkipInstallation = false +Name = Local +InsecureSkipVerify = true + +[nginx] +AccessLogPath = +ErrorLogPath = +ConfigDir = +PIDPath = +ReloadCmd = +RestartCmd = +TestConfigCmd = +LogDirWhiteList = /var/log/nginx + +[openai] +Model = gpt-4o +BaseUrl = +Proxy = +Token = + +[casdoor] +Endpoint = http://127.0.0.1:8001 +ClientId = 1234567890qwertyuiop +ClientSecret = 1234567890qwertyuiop1234567890qwertyuiop +CertificatePath = ./casdoor.pub +Organization = built-in +Application = nginx-ui-dev +RedirectUri = + +[logrotate] +Enabled = true +CMD = logrotate /etc/logrotate.d/nginx +Interval = 1440 + +[cluster] +Node = http://10.0.0.1:9000?name=test&node_secret=asdfghjklqwertyuiopzxcvbnm&enabled=true + +[auth] +IPWhiteList = 127.0.0.1 +BanThresholdMinutes = 10 +MaxAttempts = 10 + +[crypto] +Secret = 12345678901234567890 + +[webauthn] +RPDisplayName = Nginx UI +RPID = localhost +RPOrigins = http://localhost:3002,http://127.0.0.1:3002` + err := os.WriteFile(confName, []byte(confText), 0644) + if err != nil { + t.Fatalf("Failed to write config to file: %v", err) + } + + Migrate(confName) +} diff --git a/settings/settings.go b/settings/settings.go index cf9aa264..099a9b18 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -2,11 +2,11 @@ package settings import ( "github.com/caarlos0/env/v11" + "github.com/elliotchance/orderedmap/v2" "github.com/spf13/cast" - "gopkg.in/ini.v1" + "github.com/uozi-tech/cosy/settings" "log" "os" - "reflect" "strings" "time" ) @@ -14,61 +14,60 @@ import ( var ( buildTime string LastModified string - - Conf *ini.File - ConfPath string - EnvPrefix = "NGINX_UI_" + EnvPrefix = "NGINX_UI_" ) -var sections = map[string]interface{}{ - "server": &ServerSettings, - "nginx": &NginxSettings, - "openai": &OpenAISettings, - "casdoor": &CasdoorSettings, - "logrotate": &LogrotateSettings, - "cluster": &ClusterSettings, - "auth": &AuthSettings, - "crypto": &CryptoSettings, - "webauthn": &WebAuthnSettings, +var sections = orderedmap.NewOrderedMap[string, any]() + +var envPrefixMap = map[string]interface{}{ + // Cosy + "APP": settings.AppSettings, + "SERVER": settings.ServerSettings, + "DB": settings.DataBaseSettings, + // Nginx UI + "AUTH": AuthSettings, + "CASDOOR": CasdoorSettings, + "CERT": CertSettings, + "CLUSTER": ClusterSettings, + "CRYPTO": CryptoSettings, + "HTTP": HTTPSettings, + "LOGROTATE": LogrotateSettings, + "NGINX": NginxSettings, + "NODE": NodeSettings, + "OPENAI": OpenAISettings, + "TERMINAL": TerminalSettings, + "WEBAUTHN": WebAuthnSettings, } func init() { t := time.Unix(cast.ToInt64(buildTime), 0) LastModified = strings.ReplaceAll(t.Format(time.RFC1123), "UTC", "GMT") -} - -func Init(confPath string) { - ConfPath = confPath - Setup() -} -func load() (err error) { - Conf, err = ini.LoadSources(ini.LoadOptions{ - Loose: true, - AllowShadows: true, - }, ConfPath) - - return + sections.Set("auth", AuthSettings) + sections.Set("casdoor", CasdoorSettings) + sections.Set("cert", CertSettings) + sections.Set("cluster", ClusterSettings) + sections.Set("crypto", CryptoSettings) + sections.Set("http", HTTPSettings) + sections.Set("logrotate", LogrotateSettings) + sections.Set("nginx", NginxSettings) + sections.Set("node", NodeSettings) + sections.Set("openai", OpenAISettings) + sections.Set("terminal", TerminalSettings) + sections.Set("webauthn", WebAuthnSettings) + + for k, v := range sections.Iterator() { + settings.Register(k, v) + } + settings.WithoutRedis() + settings.WithoutSonyflake() } -func Setup() { - err := load() - - if err != nil { - log.Fatalf("settings.Setup: %v\n", err) +func Init() { + for prefix, ptr := range envPrefixMap { + parseEnv(ptr, prefix+"_") } - MapTo() - - parseEnv(&ServerSettings, "SERVER_") - parseEnv(&NginxSettings, "NGINX_") - parseEnv(&OpenAISettings, "OPENAI_") - parseEnv(&CasdoorSettings, "CASDOOR_") - parseEnv(&LogrotateSettings, "LOGROTATE_") - parseEnv(&AuthSettings, "AUTH_") - parseEnv(&CryptoSettings, "CRYPTO_") - parseEnv(&WebAuthnSettings, "WEBAUTHN_") - // if in official docker, set the restart cmd of nginx to "nginx -s stop", // then the supervisor of s6-overlay will start the nginx again. if cast.ToBool(os.Getenv("NGINX_UI_OFFICIAL_DOCKER")) { @@ -84,57 +83,19 @@ func Setup() { } } -func MapTo() { - for k, v := range sections { - err := mapTo(k, v) - - if err != nil { - log.Fatalf("Cfg.MapTo %s err: %v", k, err) - } - } -} - func Save() (err error) { - for k, v := range sections { - reflectFrom(k, v) - } - // fix unable to save empty slice - if len(ServerSettings.RecursiveNameservers) == 0 { - Conf.Section("server").Key("RecursiveNameservers").SetValue("") + if len(CertSettings.RecursiveNameservers) == 0 { + settings.Conf.Section("server").Key("RecursiveNameservers").SetValue("") } - err = Conf.SaveTo(ConfPath) + err = settings.Save() if err != nil { return } return } -func ProtectedFill(targetSettings interface{}, newSettings interface{}) { - s := reflect.TypeOf(targetSettings).Elem() - vt := reflect.ValueOf(targetSettings).Elem() - vn := reflect.ValueOf(newSettings).Elem() - - // copy the values from new to target settings if it is not protected - for i := 0; i < s.NumField(); i++ { - if s.Field(i).Tag.Get("protected") != "true" { - vt.Field(i).Set(vn.Field(i)) - } - } -} - -func mapTo(section string, v interface{}) error { - return Conf.Section(section).MapTo(v) -} - -func reflectFrom(section string, v interface{}) { - err := Conf.Section(section).ReflectFrom(v) - if err != nil { - log.Fatalf("Cfg.ReflectFrom %s err: %v", section, err) - } -} - func parseEnv(ptr interface{}, prefix string) { err := env.ParseWithOptions(ptr, env.Options{ Prefix: EnvPrefix + prefix, diff --git a/settings/settings_test.go b/settings/settings_test.go index ccde9725..b7ad8250 100644 --- a/settings/settings_test.go +++ b/settings/settings_test.go @@ -2,46 +2,32 @@ package settings import ( "github.com/stretchr/testify/assert" + cSettings "github.com/uozi-tech/cosy/settings" "os" "testing" ) func TestSetup(t *testing.T) { - Init("../app.example.ini") - _ = os.Setenv("NGINX_UI_OFFICIAL_DOCKER", "true") - _ = os.Setenv("NGINX_UI_SERVER_HTTP_PORT", "8080") - _ = os.Setenv("NGINX_UI_SERVER_RUN_MODE", "test") - _ = os.Setenv("NGINX_UI_SERVER_JWT_SECRET", "newSecret123") - _ = os.Setenv("NGINX_UI_SERVER_HTTP_CHALLENGE_PORT", "9181") - _ = os.Setenv("NGINX_UI_SERVER_START_CMD", "start") - _ = os.Setenv("NGINX_UI_SERVER_DATABASE", "testDB") - _ = os.Setenv("NGINX_UI_SERVER_CA_DIR", "/test/ca") - _ = os.Setenv("NGINX_UI_SERVER_GITHUB_PROXY", "http://proxy.example.com") - _ = os.Setenv("NGINX_UI_SERVER_NODE_SECRET", "nodeSecret") - _ = os.Setenv("NGINX_UI_SERVER_DEMO", "true") - _ = os.Setenv("NGINX_UI_SERVER_PAGE_SIZE", "20") - _ = os.Setenv("NGINX_UI_SERVER_HTTP_HOST", "127.0.0.1") - _ = os.Setenv("NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL", "14") - _ = os.Setenv("NGINX_UI_SERVER_RECURSIVE_NAMESERVERS", "8.8.8.8") - _ = os.Setenv("NGINX_UI_SERVER_SKIP_INSTALLATION", "true") - _ = os.Setenv("NGINX_UI_SERVER_NAME", "test") + // Server + _ = os.Setenv("NGINX_UI_SERVER_HOST", "127.0.0.1") + _ = os.Setenv("NGINX_UI_SERVER_PORT", "8080") + _ = os.Setenv("NGINX_UI_SERVER_RUN_MODE", "testing") - _ = os.Setenv("NGINX_UI_NGINX_ACCESS_LOG_PATH", "/tmp/nginx/access.log") - _ = os.Setenv("NGINX_UI_NGINX_ERROR_LOG_PATH", "/tmp/nginx/error.log") - _ = os.Setenv("NGINX_UI_NGINX_CONFIG_DIR", "/etc/nginx/conf") - _ = os.Setenv("NGINX_UI_NGINX_PID_PATH", "/var/run/nginx.pid") - _ = os.Setenv("NGINX_UI_NGINX_TEST_CONFIG_CMD", "nginx -t") - _ = os.Setenv("NGINX_UI_NGINX_RELOAD_CMD", "nginx -s reload") - _ = os.Setenv("NGINX_UI_NGINX_RESTART_CMD", "nginx -s restart") - _ = os.Setenv("NGINX_UI_NGINX_LOG_DIR_WHITE_LIST", "/var/log/nginx") + // App + _ = os.Setenv("NGINX_UI_APP_PAGE_SIZE", "20") + _ = os.Setenv("NGINX_UI_APP_JWT_SECRET", "newSecret123") - _ = os.Setenv("NGINX_UI_OPENAI_MODEL", "davinci") - _ = os.Setenv("NGINX_UI_OPENAI_BASE_URL", "https://api.openai.com") - _ = os.Setenv("NGINX_UI_OPENAI_PROXY", "https://proxy.openai.com") - _ = os.Setenv("NGINX_UI_OPENAI_TOKEN", "token123") + // Database + _ = os.Setenv("NGINX_UI_DB_NAME", "testDB") + // Auth + _ = os.Setenv("NGINX_UI_AUTH_IP_WHITE_LIST", "127.0.0.1,192.168.1.1") + _ = os.Setenv("NGINX_UI_AUTH_BAN_THRESHOLD_MINUTES", "20") + _ = os.Setenv("NGINX_UI_AUTH_MAX_ATTEMPTS", "20") + + // Casdoor _ = os.Setenv("NGINX_UI_CASDOOR_ENDPOINT", "https://casdoor.example.com") _ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_ID", "clientId") _ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_SECRET", "clientSecret") @@ -50,48 +36,80 @@ func TestSetup(t *testing.T) { _ = os.Setenv("NGINX_UI_CASDOOR_APPLICATION", "app1") _ = os.Setenv("NGINX_UI_CASDOOR_REDIRECT_URI", "https://redirect.example.com") + // Cert + _ = os.Setenv("NGINX_UI_CERT_EMAIL", "test") + _ = os.Setenv("NGINX_UI_CERT_CA_DIR", "/test/ca") + _ = os.Setenv("NGINX_UI_CERT_CERT_RENEWAL_INTERVAL", "14") + _ = os.Setenv("NGINX_UI_CERT_RECURSIVE_NAMESERVERS", "8.8.8.8,1.1.1.1") + _ = os.Setenv("NGINX_UI_CERT_HTTP_CHALLENGE_PORT", "1080") + + // Cluster + _ = os.Setenv("NGINX_UI_CLUSTER_NODE", + "http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true,"+ + "http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=false") + + // Crypto + _ = os.Setenv("NGINX_UI_CRYPTO_SECRET", "mySecret") + + // Http + _ = os.Setenv("NGINX_UI_HTTP_GITHUB_PROXY", "http://proxy.example.com") + _ = os.Setenv("NGINX_UI_HTTP_INSECURE_SKIP_VERIFY", "true") + + // Logrotate _ = os.Setenv("NGINX_UI_LOGROTATE_ENABLED", "true") _ = os.Setenv("NGINX_UI_LOGROTATE_CMD", "logrotate /custom/logrotate.conf") _ = os.Setenv("NGINX_UI_LOGROTATE_INTERVAL", "60") + // Nginx + _ = os.Setenv("NGINX_UI_NGINX_ACCESS_LOG_PATH", "/tmp/nginx/access.log") + _ = os.Setenv("NGINX_UI_NGINX_ERROR_LOG_PATH", "/tmp/nginx/error.log") + _ = os.Setenv("NGINX_UI_NGINX_CONFIG_DIR", "/etc/nginx/conf") + _ = os.Setenv("NGINX_UI_NGINX_PID_PATH", "/var/run/nginx.pid") + _ = os.Setenv("NGINX_UI_NGINX_TEST_CONFIG_CMD", "nginx -t") + _ = os.Setenv("NGINX_UI_NGINX_RELOAD_CMD", "nginx -s reload") + _ = os.Setenv("NGINX_UI_NGINX_RESTART_CMD", "nginx -s restart") + _ = os.Setenv("NGINX_UI_NGINX_LOG_DIR_WHITE_LIST", "/var/log/nginx") + + // Node + _ = os.Setenv("NGINX_UI_NODE_NAME", "test") + _ = os.Setenv("NGINX_UI_NODE_NODE_SECRET", "nodeSecret") + _ = os.Setenv("NGINX_UI_NODE_SKIP_INSTALLATION", "true") + _ = os.Setenv("NGINX_UI_NODE_DEMO", "true") + + // OpenAI + _ = os.Setenv("NGINX_UI_OPENAI_MODEL", "gpt4o") + _ = os.Setenv("NGINX_UI_OPENAI_BASE_URL", "https://api.openai.com") + _ = os.Setenv("NGINX_UI_OPENAI_PROXY", "https://proxy.openai.com") + _ = os.Setenv("NGINX_UI_OPENAI_TOKEN", "token123") + + // Terminal + _ = os.Setenv("NGINX_UI_TERMINAL_START_CMD", "bash") + + // WebAuthn _ = os.Setenv("NGINX_UI_WEBAUTHN_RP_DISPLAY_NAME", "WebAuthn") _ = os.Setenv("NGINX_UI_WEBAUTHN_RPID", "localhost") _ = os.Setenv("NGINX_UI_WEBAUTHN_RP_ORIGINS", "http://localhost:3002") - ConfPath = "app.testing.ini" - Setup() - - assert.Equal(t, "8080", ServerSettings.HttpPort) - assert.Equal(t, "test", ServerSettings.RunMode) - assert.Equal(t, "newSecret123", ServerSettings.JwtSecret) - assert.Equal(t, "9181", ServerSettings.HTTPChallengePort) - assert.Equal(t, "start", ServerSettings.StartCmd) - assert.Equal(t, "testDB", ServerSettings.Database) - assert.Equal(t, "/test/ca", ServerSettings.CADir) - assert.Equal(t, "http://proxy.example.com", ServerSettings.GithubProxy) - assert.Equal(t, "nodeSecret", ServerSettings.NodeSecret) - assert.Equal(t, true, ServerSettings.Demo) - assert.Equal(t, 20, ServerSettings.PageSize) - assert.Equal(t, "127.0.0.1", ServerSettings.HttpHost) - assert.Equal(t, 14, ServerSettings.CertRenewalInterval) - assert.Equal(t, []string{"8.8.8.8"}, ServerSettings.RecursiveNameservers) - assert.Equal(t, true, ServerSettings.SkipInstallation) - assert.Equal(t, "test", ServerSettings.Name) + Init() - assert.Equal(t, "/tmp/nginx/access.log", NginxSettings.AccessLogPath) - assert.Equal(t, "/tmp/nginx/error.log", NginxSettings.ErrorLogPath) - assert.Equal(t, "/etc/nginx/conf", NginxSettings.ConfigDir) - assert.Equal(t, "/var/run/nginx.pid", NginxSettings.PIDPath) - assert.Equal(t, "nginx -t", NginxSettings.TestConfigCmd) - assert.Equal(t, "nginx -s reload", NginxSettings.ReloadCmd) - assert.Equal(t, "nginx -s stop", NginxSettings.RestartCmd) - assert.Equal(t, []string{"/var/log/nginx"}, NginxSettings.LogDirWhiteList) + // Server + assert.Equal(t, "127.0.0.1", cSettings.ServerSettings.Host) + assert.Equal(t, uint(8080), cSettings.ServerSettings.Port) + assert.Equal(t, "testing", cSettings.ServerSettings.RunMode) - assert.Equal(t, "davinci", OpenAISettings.Model) - assert.Equal(t, "https://api.openai.com", OpenAISettings.BaseUrl) - assert.Equal(t, "https://proxy.openai.com", OpenAISettings.Proxy) - assert.Equal(t, "token123", OpenAISettings.Token) + // App + assert.Equal(t, 20, cSettings.AppSettings.PageSize) + assert.Equal(t, "newSecret123", cSettings.AppSettings.JwtSecret) + + // Database + assert.Equal(t, "testDB", cSettings.DataBaseSettings.Name) + // Auth + assert.Equal(t, []string{"127.0.0.1", "192.168.1.1"}, AuthSettings.IPWhiteList) + assert.Equal(t, 20, AuthSettings.BanThresholdMinutes) + assert.Equal(t, 20, AuthSettings.MaxAttempts) + + // Casdoor assert.Equal(t, "https://casdoor.example.com", CasdoorSettings.Endpoint) assert.Equal(t, "clientId", CasdoorSettings.ClientId) assert.Equal(t, "clientSecret", CasdoorSettings.ClientSecret) @@ -100,14 +118,61 @@ func TestSetup(t *testing.T) { assert.Equal(t, "app1", CasdoorSettings.Application) assert.Equal(t, "https://redirect.example.com", CasdoorSettings.RedirectUri) + // Cert + assert.Equal(t, "test", CertSettings.Email) + assert.Equal(t, "1080", CertSettings.HTTPChallengePort) + assert.Equal(t, "/test/ca", CertSettings.CADir) + assert.Equal(t, 14, CertSettings.RenewalInterval) + assert.Equal(t, []string{"8.8.8.8", "1.1.1.1"}, CertSettings.RecursiveNameservers) + + // Cluster + assert.Equal(t, + []string{ + "http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true", + "http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=false"}, + ClusterSettings.Node) + + // Crypto + assert.Equal(t, "mySecret", CryptoSettings.Secret) + + // Http + assert.Equal(t, "http://proxy.example.com", HTTPSettings.GithubProxy) + assert.Equal(t, true, HTTPSettings.InsecureSkipVerify) + + // Logrotate assert.Equal(t, true, LogrotateSettings.Enabled) assert.Equal(t, "logrotate /custom/logrotate.conf", LogrotateSettings.CMD) assert.Equal(t, 60, LogrotateSettings.Interval) + // Nginx + assert.Equal(t, "/tmp/nginx/access.log", NginxSettings.AccessLogPath) + assert.Equal(t, "/tmp/nginx/error.log", NginxSettings.ErrorLogPath) + assert.Equal(t, "/etc/nginx/conf", NginxSettings.ConfigDir) + assert.Equal(t, "/var/run/nginx.pid", NginxSettings.PIDPath) + assert.Equal(t, "nginx -t", NginxSettings.TestConfigCmd) + assert.Equal(t, "nginx -s reload", NginxSettings.ReloadCmd) + assert.Equal(t, "nginx -s stop", NginxSettings.RestartCmd) + assert.Equal(t, []string{"/var/log/nginx"}, NginxSettings.LogDirWhiteList) + + // Node + assert.Equal(t, "test", NodeSettings.Name) + assert.Equal(t, "nodeSecret", NodeSettings.Secret) + assert.Equal(t, true, NodeSettings.SkipInstallation) + assert.Equal(t, true, NodeSettings.Demo) + + // OpenAI + assert.Equal(t, "gpt4o", OpenAISettings.Model) + assert.Equal(t, "https://api.openai.com", OpenAISettings.BaseUrl) + assert.Equal(t, "https://proxy.openai.com", OpenAISettings.Proxy) + assert.Equal(t, "token123", OpenAISettings.Token) + + // Terminal + assert.Equal(t, "bash", TerminalSettings.StartCmd) + + // WebAuthn assert.Equal(t, "WebAuthn", WebAuthnSettings.RPDisplayName) assert.Equal(t, "localhost", WebAuthnSettings.RPID) assert.Equal(t, []string{"http://localhost:3002"}, WebAuthnSettings.RPOrigins) os.Clearenv() - _ = os.Remove("app.testing.ini") } diff --git a/settings/terminal.go b/settings/terminal.go new file mode 100644 index 00000000..bbae1a6c --- /dev/null +++ b/settings/terminal.go @@ -0,0 +1,7 @@ +package settings + +type Terminal struct { + StartCmd string `json:"start_cmd" protected:"true"` +} + +var TerminalSettings = &Terminal{} diff --git a/settings/webauthn.go b/settings/webauthn.go index 84e01b8b..e35d5acf 100644 --- a/settings/webauthn.go +++ b/settings/webauthn.go @@ -6,4 +6,4 @@ type WebAuthn struct { RPOrigins []string } -var WebAuthnSettings = WebAuthn{} +var WebAuthnSettings = &WebAuthn{} From 918f920d577a59a7df26da6870a4698d69517dda Mon Sep 17 00:00:00 2001 From: Jacky Date: Tue, 22 Oct 2024 17:27:40 +0800 Subject: [PATCH 02/13] fix: gen code generator; some unit tests --- api/user/passkey.go | 10 ++-- app/src/views/other/Login.vue | 3 ++ cmd/generate/generate.go | 16 +++---- internal/cluster/cluster_test.go | 77 ++++++++++++++++-------------- internal/cron/cron_test.go | 22 --------- settings/app.testing.ini | 82 -------------------------------- settings/settings_test.go | 4 +- test/chatgpt_test.go | 76 +++++++++++++++-------------- 8 files changed, 99 insertions(+), 191 deletions(-) delete mode 100644 internal/cron/cron_test.go delete mode 100644 settings/app.testing.ini diff --git a/api/user/passkey.go b/api/user/passkey.go index c27260e3..9df1d632 100644 --- a/api/user/passkey.go +++ b/api/user/passkey.go @@ -152,11 +152,13 @@ func FinishPasskeyLogin(c *gin.Context) { return } + secureSessionID := user.SetSecureSessionID(outUser.ID) + c.JSON(http.StatusOK, LoginResponse{ - Code: LoginSuccess, - Message: "ok", - Token: token, - // SecureSessionID: secureSessionID, + Code: LoginSuccess, + Message: "ok", + Token: token, + SecureSessionID: secureSessionID, }) } diff --git a/app/src/views/other/Login.vue b/app/src/views/other/Login.vue index 458beefb..64c88d7a 100644 --- a/app/src/views/other/Login.vue +++ b/app/src/views/other/Login.vue @@ -167,9 +167,12 @@ async function handlePasskeyLogin() { }) if (r.token) { + const cookies = useCookies(['nginx-ui-2fa']) const next = (route.query?.next || '').toString() || '/' passkeyLogin(asseResp.rawId, r.token) + secureSessionId.value = r.secure_session_id + cookies.set('secure_session_id', r.secure_session_id, { maxAge: 60 * 3 }) await router.push(next) } diff --git a/cmd/generate/generate.go b/cmd/generate/generate.go index 1e5c1e9d..27ff6324 100644 --- a/cmd/generate/generate.go +++ b/cmd/generate/generate.go @@ -4,7 +4,7 @@ import ( "flag" "fmt" "github.com/0xJacky/Nginx-UI/model" - "github.com/0xJacky/Nginx-UI/settings" + "github.com/uozi-tech/cosy/settings" "gorm.io/driver/sqlite" "gorm.io/gen" "gorm.io/gorm" @@ -21,26 +21,26 @@ func main() { Mode: gen.WithoutContext | gen.WithDefaultQuery, //if you want the nullable field generation property to be pointer type, set FieldNullable true FieldNullable: true, - //if you want to assign field which has default value in `Create` API, set FieldCoverable true, reference: https://gorm.io/docs/create.html#Default-Values + //if you want to assign field which has the default value in `Create` API, set FieldCoverable true, reference: https://gorm.io/docs/create.html#Default-Values FieldCoverable: true, - // if you want to generate field with unsigned integer type, set FieldSignable true + // if you want to generate field with an unsigned integer type, set FieldSignable true /* FieldSignable: true,*/ - //if you want to generate index tags from database, set FieldWithIndexTag true + //if you want to generate index tags from the database, set FieldWithIndexTag true /* FieldWithIndexTag: true,*/ - //if you want to generate type tags from database, set FieldWithTypeTag true + //if you want to generate type tags from the database, set FieldWithTypeTag true /* FieldWithTypeTag: true,*/ //if you need unit tests for query code, set WithUnitTest true /* WithUnitTest: true, */ }) // reuse the database connection in Project or create a connection here - // if you want to use GenerateModel/GenerateModelAs, UseDB is necessary or it will panic + // if you want to use GenerateModel/GenerateModelAs, UseDB is necessary, or it will panic var confPath string flag.StringVar(&confPath, "config", "app.ini", "Specify the configuration file") flag.Parse() settings.Init(confPath) - dbPath := path.Join(path.Dir(settings.ConfPath), fmt.Sprintf("%s.db", settings.ServerSettings.Database)) + dbPath := path.Join(path.Dir(confPath), fmt.Sprintf("%s.db", settings.DataBaseSettings.Name)) var err error db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{ @@ -56,7 +56,7 @@ func main() { g.UseDB(db) // apply basic crud api on structs or table models which is specified by table name with function - // GenerateModel/GenerateModelAs. And generator will generate table models' code when calling Excute. + // GenerateModel/GenerateModelAs. And the generator will generate table models' code when calling Excute. g.ApplyBasic(model.GenerateAllModel()...) // apply diy interfaces on structs or table models diff --git a/internal/cluster/cluster_test.go b/internal/cluster/cluster_test.go index da67123e..c48c0e21 100644 --- a/internal/cluster/cluster_test.go +++ b/internal/cluster/cluster_test.go @@ -3,45 +3,48 @@ package cluster import ( "github.com/0xJacky/Nginx-UI/settings" "github.com/stretchr/testify/assert" + "github.com/uozi-tech/cosy/sandbox" "testing" ) func Test_parseNodeUrl(t *testing.T) { - settings.Init("../../app.example.ini") - t.Log(settings.ClusterSettings.Node) - node := settings.ClusterSettings.Node[0] - - env, err := parseNodeUrl(node) - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, "node1", env.Name) - assert.Equal(t, "http://10.0.0.1:9000", env.URL) - assert.Equal(t, "my-node-secret", env.Token) - assert.Equal(t, true, env.Enabled) - - node = settings.ClusterSettings.Node[1] - - env, err = parseNodeUrl(node) - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, "node2", env.Name) - assert.Equal(t, "http://10.0.0.2:9000", env.URL) - assert.Equal(t, "my-node-secret", env.Token) - assert.Equal(t, true, env.Enabled) - - node = settings.ClusterSettings.Node[2] - - env, err = parseNodeUrl(node) - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, "node3", env.Name) - assert.Equal(t, "http://10.0.0.3", env.URL) - assert.Equal(t, "my-node-secret", env.Token) - assert.Equal(t, true, env.Enabled) + sandbox.NewInstance("../../app.example.ini", "sqlite"). + Run(func(instance *sandbox.Instance) { + t.Log(settings.ClusterSettings.Node) + node := settings.ClusterSettings.Node[0] + + env, err := parseNodeUrl(node) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "node1", env.Name) + assert.Equal(t, "http://10.0.0.1:9000", env.URL) + assert.Equal(t, "my-node-secret", env.Token) + assert.Equal(t, true, env.Enabled) + + node = settings.ClusterSettings.Node[1] + + env, err = parseNodeUrl(node) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "node2", env.Name) + assert.Equal(t, "http://10.0.0.2:9000", env.URL) + assert.Equal(t, "my-node-secret", env.Token) + assert.Equal(t, true, env.Enabled) + + node = settings.ClusterSettings.Node[2] + + env, err = parseNodeUrl(node) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "node3", env.Name) + assert.Equal(t, "http://10.0.0.3", env.URL) + assert.Equal(t, "my-node-secret", env.Token) + assert.Equal(t, true, env.Enabled) + }) } diff --git a/internal/cron/cron_test.go b/internal/cron/cron_test.go deleted file mode 100644 index 8b19de90..00000000 --- a/internal/cron/cron_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package cron - -import ( - "github.com/0xJacky/Nginx-UI/internal/kernal" - "github.com/0xJacky/Nginx-UI/settings" - "testing" - "time" -) - -func TestRestartLogrotate(t *testing.T) { - settings.Init("../../app.ini") - - kernal.InitDatabase() - - InitCronJobs() - - time.Sleep(5 * time.Second) - - RestartLogrotate() - - time.Sleep(2 * time.Second) -} diff --git a/settings/app.testing.ini b/settings/app.testing.ini deleted file mode 100644 index 76d3b1c4..00000000 --- a/settings/app.testing.ini +++ /dev/null @@ -1,82 +0,0 @@ -[app] -PageSize = 20 -JwtSecret = newSecret - -[server] -Host = 0.0.0.0 -Port = 9000 -RunMode = debug - -[database] -Host = -Port = 0 -User = -Password = -Name = database -TablePrefix = - -[auth] -IPWhiteList = 127.0.0.1 -BanThresholdMinutes = 10 -MaxAttempts = 10 - -[casdoor] -Endpoint = http://127.0.0.1:8001 -ClientId = 1234567890qwertyuiop -ClientSecret = 1234567890qwertyuiop1234567890qwertyuiop -CertificatePath = ./casdoor.pub -Organization = built-in -Application = nginx-ui-dev -RedirectUri = - -[cert] -Email = test -CADir = /test -CertRenewalInterval = 7 -RecursiveNameservers = 8.8.8.8,1.1.1.1 -HTTPChallengePort = 9181 - -[cluster] -Node = http://10.0.0.1:9000?name=test&node_secret=asdfghjklqwertyuiopzxcvbnm&enabled=true - -[crypto] -Secret = 12345678901234567890 - -[http] -GithubProxy = https://mirror.ghproxy.com/ -InsecureSkipVerify = true - -[logrotate] -Enabled = true -CMD = logrotate /etc/logrotate.d/nginx -Interval = 1440 - -[nginx] -AccessLogPath = -ErrorLogPath = -LogDirWhiteList = /var/log/nginx -ConfigDir = -PIDPath = -TestConfigCmd = -ReloadCmd = -RestartCmd = - -[node] -Name = Local -Secret = -SkipInstallation = false -Demo = false - -[openai] -BaseUrl = -Token = -Proxy = -Model = gpt-4o - -[terminal] -StartCmd = bash - -[webauthn] -RPDisplayName = Nginx UI -RPID = localhost -RPOrigins = http://localhost:3002,http://127.0.0.1:3002 diff --git a/settings/settings_test.go b/settings/settings_test.go index b7ad8250..6b1f725d 100644 --- a/settings/settings_test.go +++ b/settings/settings_test.go @@ -39,7 +39,7 @@ func TestSetup(t *testing.T) { // Cert _ = os.Setenv("NGINX_UI_CERT_EMAIL", "test") _ = os.Setenv("NGINX_UI_CERT_CA_DIR", "/test/ca") - _ = os.Setenv("NGINX_UI_CERT_CERT_RENEWAL_INTERVAL", "14") + _ = os.Setenv("NGINX_UI_CERT_RENEWAL_INTERVAL", "14") _ = os.Setenv("NGINX_UI_CERT_RECURSIVE_NAMESERVERS", "8.8.8.8,1.1.1.1") _ = os.Setenv("NGINX_UI_CERT_HTTP_CHALLENGE_PORT", "1080") @@ -72,7 +72,7 @@ func TestSetup(t *testing.T) { // Node _ = os.Setenv("NGINX_UI_NODE_NAME", "test") - _ = os.Setenv("NGINX_UI_NODE_NODE_SECRET", "nodeSecret") + _ = os.Setenv("NGINX_UI_NODE_SECRET", "nodeSecret") _ = os.Setenv("NGINX_UI_NODE_SKIP_INSTALLATION", "true") _ = os.Setenv("NGINX_UI_NODE_DEMO", "true") diff --git a/test/chatgpt_test.go b/test/chatgpt_test.go index d7726876..d494c0ac 100644 --- a/test/chatgpt_test.go +++ b/test/chatgpt_test.go @@ -6,46 +6,50 @@ import ( "github.com/0xJacky/Nginx-UI/settings" "github.com/pkg/errors" "github.com/sashabaranov/go-openai" + "github.com/uozi-tech/cosy/sandbox" "io" "os" "testing" ) func TestChatGPT(t *testing.T) { - settings.Init("../../app.ini") - c := openai.NewClient(settings.OpenAISettings.Token) - - ctx := context.Background() - - req := openai.ChatCompletionRequest{ - Model: openai.GPT3Dot5Turbo0301, - Messages: []openai.ChatCompletionMessage{ - { - Role: openai.ChatMessageRoleUser, - Content: "帮我写一个 nginx 配置文件的示例", - }, - }, - Stream: true, - } - stream, err := c.CreateChatCompletionStream(ctx, req) - if err != nil { - fmt.Printf("CompletionStream error: %v\n", err) - return - } - defer stream.Close() - - for { - response, err := stream.Recv() - if errors.Is(err, io.EOF) { - return - } - - if err != nil { - fmt.Printf("Stream error: %v\n", err) - return - } - - fmt.Printf("%v", response.Choices[0].Delta.Content) - _ = os.Stdout.Sync() - } + sandbox.NewInstance("../../app.ini", "sqlite"). + Run(func(instance *sandbox.Instance) { + c := openai.NewClient(settings.OpenAISettings.Token) + + ctx := context.Background() + + req := openai.ChatCompletionRequest{ + Model: openai.GPT3Dot5Turbo0301, + Messages: []openai.ChatCompletionMessage{ + { + Role: openai.ChatMessageRoleUser, + Content: "帮我写一个 nginx 配置文件的示例", + }, + }, + Stream: true, + } + stream, err := c.CreateChatCompletionStream(ctx, req) + if err != nil { + fmt.Printf("CompletionStream error: %v\n", err) + return + } + defer stream.Close() + + for { + response, err := stream.Recv() + if errors.Is(err, io.EOF) { + return + } + + if err != nil { + fmt.Printf("Stream error: %v\n", err) + return + } + + fmt.Printf("%v", response.Choices[0].Delta.Content) + _ = os.Stdout.Sync() + } + }) + } From 60034145fa02cd922aa66ee31a4a34b85e49f081 Mon Sep 17 00:00:00 2001 From: Jacky Date: Tue, 22 Oct 2024 17:44:43 +0800 Subject: [PATCH 03/13] chore: update deps --- app/package.json | 6 +-- app/pnpm-lock.yaml | 126 ++++++++++++++++++++++----------------------- 2 files changed, 66 insertions(+), 66 deletions(-) diff --git a/app/package.json b/app/package.json index d6cc5c7c..cac2c138 100644 --- a/app/package.json +++ b/app/package.json @@ -49,7 +49,7 @@ "devDependencies": { "@antfu/eslint-config-vue": "^0.43.1", "@simplewebauthn/types": "^10.0.0", - "@types/lodash": "^4.17.11", + "@types/lodash": "^4.17.12", "@types/nprogress": "^0.2.3", "@types/sortablejs": "^1.15.8", "@typescript-eslint/eslint-plugin": "^6.21.0", @@ -58,7 +58,7 @@ "@vitejs/plugin-vue-jsx": "^4.0.1", "@vue/compiler-sfc": "^3.5.12", "@vue/tsconfig": "^0.5.1", - "ace-builds": "^1.36.2", + "ace-builds": "^1.36.3", "autoprefixer": "^10.4.20", "eslint": "^8.57.1", "eslint-import-resolver-alias": "^1.1.2", @@ -66,7 +66,7 @@ "eslint-plugin-import": "^2.31.0", "eslint-plugin-regex": "^1.10.0", "eslint-plugin-sonarjs": "^0.23.0", - "eslint-plugin-vue": "^9.29.0", + "eslint-plugin-vue": "^9.29.1", "less": "^4.2.0", "postcss": "^8.4.47", "tailwindcss": "^3.4.14", diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml index 1dc34cf2..0c5c7386 100644 --- a/app/pnpm-lock.yaml +++ b/app/pnpm-lock.yaml @@ -97,7 +97,7 @@ importers: version: 4.4.5(vue@3.5.12(typescript@5.3.3)) vue3-ace-editor: specifier: 2.2.4 - version: 2.2.4(ace-builds@1.36.2)(vue@3.5.12(typescript@5.3.3)) + version: 2.2.4(ace-builds@1.36.3)(vue@3.5.12(typescript@5.3.3)) vue3-apexcharts: specifier: 1.5.3 version: 1.5.3(apexcharts@3.54.1)(vue@3.5.12(typescript@5.3.3)) @@ -113,13 +113,13 @@ importers: devDependencies: '@antfu/eslint-config-vue': specifier: ^0.43.1 - version: 0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)(typescript@5.3.3) + version: 0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(typescript@5.3.3) '@simplewebauthn/types': specifier: ^10.0.0 version: 10.0.0 '@types/lodash': - specifier: ^4.17.11 - version: 4.17.11 + specifier: ^4.17.12 + version: 4.17.12 '@types/nprogress': specifier: ^0.2.3 version: 0.2.3 @@ -134,10 +134,10 @@ importers: version: 6.21.0(eslint@8.57.1)(typescript@5.3.3) '@vitejs/plugin-vue': specifier: ^5.1.4 - version: 5.1.4(vite@5.4.9(@types/node@22.7.6)(less@4.2.0))(vue@3.5.12(typescript@5.3.3)) + version: 5.1.4(vite@5.4.9(@types/node@22.7.8)(less@4.2.0))(vue@3.5.12(typescript@5.3.3)) '@vitejs/plugin-vue-jsx': specifier: ^4.0.1 - version: 4.0.1(vite@5.4.9(@types/node@22.7.6)(less@4.2.0))(vue@3.5.12(typescript@5.3.3)) + version: 4.0.1(vite@5.4.9(@types/node@22.7.8)(less@4.2.0))(vue@3.5.12(typescript@5.3.3)) '@vue/compiler-sfc': specifier: ^3.5.12 version: 3.5.12 @@ -145,8 +145,8 @@ importers: specifier: ^0.5.1 version: 0.5.1 ace-builds: - specifier: ^1.36.2 - version: 1.36.2 + specifier: ^1.36.3 + version: 1.36.3 autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47) @@ -155,7 +155,7 @@ importers: version: 8.57.1 eslint-import-resolver-alias: specifier: ^1.1.2 - version: 1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)) + version: 1.1.2(eslint-plugin-import@2.31.0) eslint-import-resolver-typescript: specifier: ^3.6.3 version: 3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1) @@ -169,8 +169,8 @@ importers: specifier: ^0.23.0 version: 0.23.0(eslint@8.57.1) eslint-plugin-vue: - specifier: ^9.29.0 - version: 9.29.0(eslint@8.57.1) + specifier: ^9.29.1 + version: 9.29.1(eslint@8.57.1) less: specifier: ^4.2.0 version: 4.2.0 @@ -194,7 +194,7 @@ importers: version: 1.5.2(rollup@4.24.0)(vue@3.5.12(typescript@5.3.3))(webpack-sources@3.2.3) vite: specifier: ^5.4.9 - version: 5.4.9(@types/node@22.7.6)(less@4.2.0) + version: 5.4.9(@types/node@22.7.8)(less@4.2.0) vite-svg-loader: specifier: ^5.1.0 version: 5.1.0(vue@3.5.12(typescript@5.3.3)) @@ -746,8 +746,8 @@ packages: '@types/json5@0.0.29': resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - '@types/lodash@4.17.11': - resolution: {integrity: sha512-jzqWo/uQP/iqeGGTjhgFp2yaCrCYTauASQcpdzESNCkHjSprBJVcZP9KG9aQ0q+xcsXiKd/iuw/4dLjS3Odc7Q==} + '@types/lodash@4.17.12': + resolution: {integrity: sha512-sviUmCE8AYdaF/KIHLDJBQgeYzPBI0vf/17NaYehBJfYD1j6/L95Slh07NlyK2iNyBNaEkb3En2jRt+a8y3xZQ==} '@types/mdast@3.0.15': resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} @@ -755,11 +755,11 @@ packages: '@types/minimatch@5.1.2': resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - '@types/node@20.16.12': - resolution: {integrity: sha512-LfPFB0zOeCeCNQV3i+67rcoVvoN5n0NVuR2vLG0O5ySQMgchuZlC4lgz546ZOJyDtj5KIgOxy+lacOimfqZAIA==} + '@types/node@20.16.14': + resolution: {integrity: sha512-vtgGzjxLF7QT88qRHtXMzCWpAAmwonE7fwgVjFtXosUva2oSpnIEc3gNO9P7uIfOxKnii2f79/xtOnfreYtDaA==} - '@types/node@22.7.6': - resolution: {integrity: sha512-/d7Rnj0/ExXDMcioS78/kf1lMzYk4BZV8MZGTBKzTGZ6/406ukkbYlIsZmMPhcR5KlkunDHQLrtAVmSq7r+mSw==} + '@types/node@22.7.8': + resolution: {integrity: sha512-a922jJy31vqR5sk+kAdIENJjHblqcZ4RmERviFsER4WJcEONqxKcjNOlk0q7OUfrF5sddT+vng070cdfMlrPLg==} '@types/normalize-package-data@2.4.4': resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -1033,8 +1033,8 @@ packages: '@yr/monotone-cubic-spline@1.0.3': resolution: {integrity: sha512-FQXkOta0XBSUPHndIKON2Y9JeQz5ZeMqLYZVVK93FliNBFm7LNMIZmY6FrMEB9XPcDbE2bekMbZD6kzDkxwYjA==} - ace-builds@1.36.2: - resolution: {integrity: sha512-eqqfbGwx/GKjM/EnFu4QtQ+d2NNBu84MGgxoG8R5iyFpcVeQ4p9YlTL+ZzdEJqhdkASqoqOxCSNNGyB6lvMm+A==} + ace-builds@1.36.3: + resolution: {integrity: sha512-YcdwV2IIaJSfjkWAR1NEYN5IxBiXefTgwXsJ//UlaFrjXDX5hQpvPFvEePHz2ZBUfvO54RjHeRUQGX8MS5HaMQ==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -1181,8 +1181,8 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - browserslist@4.24.0: - resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} + browserslist@4.24.2: + resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1478,8 +1478,8 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - electron-to-chromium@1.5.41: - resolution: {integrity: sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==} + electron-to-chromium@1.5.42: + resolution: {integrity: sha512-gIfKavKDw1mhvic9nbzA5lZw8QSHpdMwLwXc0cWidQz9B15pDoDdDH4boIatuFfeoCatb3a/NGL6CYRVFxGZ9g==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1712,8 +1712,8 @@ packages: '@typescript-eslint/eslint-plugin': optional: true - eslint-plugin-vue@9.29.0: - resolution: {integrity: sha512-hamyjrBhNH6Li6R1h1VF9KHfshJlKgKEg3ARbGTn72CMNDSMhWbgC7NdkRDEh25AFW+4SDATzyNM+3gWuZii8g==} + eslint-plugin-vue@9.29.1: + resolution: {integrity: sha512-MH/MbVae4HV/tM8gKAVWMPJbYgW04CK7SuzYRrlNERpxbO0P3+Zdsa2oAcFBW6xNu7W6lIkGOsFAMCRTYmrlWQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 @@ -3403,14 +3403,14 @@ snapshots: '@ant-design/icons-svg': 4.4.2 vue: 3.5.12(typescript@5.3.3) - '@antfu/eslint-config-basic@0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)(typescript@5.3.3)': + '@antfu/eslint-config-basic@0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(typescript@5.3.3)': dependencies: '@stylistic/eslint-plugin-js': 0.0.4 eslint: 8.57.1 eslint-plugin-antfu: 0.43.1(eslint@8.57.1)(typescript@5.3.3) eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.1) eslint-plugin-html: 7.1.0 - eslint-plugin-import: eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsdoc: 46.10.1(eslint@8.57.1) eslint-plugin-jsonc: 2.16.0(eslint@8.57.1) eslint-plugin-markdown: 3.0.1(eslint@8.57.1) @@ -3430,9 +3430,9 @@ snapshots: - supports-color - typescript - '@antfu/eslint-config-ts@0.43.1(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)(typescript@5.3.3)': + '@antfu/eslint-config-ts@0.43.1(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(typescript@5.3.3)': dependencies: - '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)(typescript@5.3.3) + '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(typescript@5.3.3) '@stylistic/eslint-plugin-ts': 0.0.4(eslint@8.57.1)(typescript@5.3.3) '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3) '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.3.3) @@ -3445,12 +3445,12 @@ snapshots: - jest - supports-color - '@antfu/eslint-config-vue@0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)(typescript@5.3.3)': + '@antfu/eslint-config-vue@0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(typescript@5.3.3)': dependencies: - '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)(typescript@5.3.3) - '@antfu/eslint-config-ts': 0.43.1(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1)(typescript@5.3.3) + '@antfu/eslint-config-basic': 0.43.1(@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3))(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(typescript@5.3.3) + '@antfu/eslint-config-ts': 0.43.1(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)(typescript@5.3.3) eslint: 8.57.1 - eslint-plugin-vue: 9.29.0(eslint@8.57.1) + eslint-plugin-vue: 9.29.1(eslint@8.57.1) local-pkg: 0.4.3 transitivePeerDependencies: - '@typescript-eslint/eslint-plugin' @@ -3505,7 +3505,7 @@ snapshots: dependencies: '@babel/compat-data': 7.25.8 '@babel/helper-validator-option': 7.25.7 - browserslist: 4.24.0 + browserslist: 4.24.2 lru-cache: 5.1.1 semver: 6.3.1 @@ -3959,13 +3959,13 @@ snapshots: '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 - '@types/node': 22.7.6 + '@types/node': 22.7.8 '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} - '@types/lodash@4.17.11': {} + '@types/lodash@4.17.12': {} '@types/mdast@3.0.15': dependencies: @@ -3973,11 +3973,11 @@ snapshots: '@types/minimatch@5.1.2': {} - '@types/node@20.16.12': + '@types/node@20.16.14': dependencies: undici-types: 6.19.8 - '@types/node@22.7.6': + '@types/node@22.7.8': dependencies: undici-types: 6.19.8 @@ -4124,19 +4124,19 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-vue-jsx@4.0.1(vite@5.4.9(@types/node@22.7.6)(less@4.2.0))(vue@3.5.12(typescript@5.3.3))': + '@vitejs/plugin-vue-jsx@4.0.1(vite@5.4.9(@types/node@22.7.8)(less@4.2.0))(vue@3.5.12(typescript@5.3.3))': dependencies: '@babel/core': 7.25.8 '@babel/plugin-transform-typescript': 7.25.7(@babel/core@7.25.8) '@vue/babel-plugin-jsx': 1.2.5(@babel/core@7.25.8) - vite: 5.4.9(@types/node@22.7.6)(less@4.2.0) + vite: 5.4.9(@types/node@22.7.8)(less@4.2.0) vue: 3.5.12(typescript@5.3.3) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@5.1.4(vite@5.4.9(@types/node@22.7.6)(less@4.2.0))(vue@3.5.12(typescript@5.3.3))': + '@vitejs/plugin-vue@5.1.4(vite@5.4.9(@types/node@22.7.8)(less@4.2.0))(vue@3.5.12(typescript@5.3.3))': dependencies: - vite: 5.4.9(@types/node@22.7.6)(less@4.2.0) + vite: 5.4.9(@types/node@22.7.8)(less@4.2.0) vue: 3.5.12(typescript@5.3.3) '@volar/language-core@2.4.6': @@ -4325,7 +4325,7 @@ snapshots: '@yr/monotone-cubic-spline@1.0.3': {} - ace-builds@1.36.2: {} + ace-builds@1.36.3: {} acorn-jsx@5.3.2(acorn@8.13.0): dependencies: @@ -4475,7 +4475,7 @@ snapshots: autoprefixer@10.4.20(postcss@8.4.47): dependencies: - browserslist: 4.24.0 + browserslist: 4.24.2 caniuse-lite: 1.0.30001669 fraction.js: 4.3.7 normalize-range: 0.1.2 @@ -4514,12 +4514,12 @@ snapshots: dependencies: fill-range: 7.1.1 - browserslist@4.24.0: + browserslist@4.24.2: dependencies: caniuse-lite: 1.0.30001669 - electron-to-chromium: 1.5.41 + electron-to-chromium: 1.5.42 node-releases: 2.0.18 - update-browserslist-db: 1.1.1(browserslist@4.24.0) + update-browserslist-db: 1.1.1(browserslist@4.24.2) builtin-modules@3.3.0: {} @@ -4797,7 +4797,7 @@ snapshots: eastasianwidth@0.2.0: {} - electron-to-chromium@1.5.41: {} + electron-to-chromium@1.5.42: {} emoji-regex@8.0.0: {} @@ -4935,7 +4935,7 @@ snapshots: eslint: 8.57.1 semver: 7.6.3 - eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1)): + eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.31.0): dependencies: eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) @@ -4953,7 +4953,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -4966,7 +4966,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -5002,13 +5002,13 @@ snapshots: dependencies: htmlparser2: 8.0.2 - eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1): + eslint-plugin-i@2.28.1(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) get-tsconfig: 4.8.1 is-glob: 4.0.3 minimatch: 3.1.2 @@ -5031,7 +5031,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-plugin-import@2.31.0)(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -5147,7 +5147,7 @@ snapshots: optionalDependencies: '@typescript-eslint/eslint-plugin': 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.3.3))(eslint@8.57.1)(typescript@5.3.3) - eslint-plugin-vue@9.29.0(eslint@8.57.1): + eslint-plugin-vue@9.29.1(eslint@8.57.1): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) eslint: 8.57.1 @@ -6734,9 +6734,9 @@ snapshots: transitivePeerDependencies: - supports-color - update-browserslist-db@1.1.1(browserslist@4.24.0): + update-browserslist-db@1.1.1(browserslist@4.24.2): dependencies: - browserslist: 4.24.0 + browserslist: 4.24.2 escalade: 3.2.0 picocolors: 1.1.1 @@ -6753,7 +6753,7 @@ snapshots: vite-plugin-build-id@0.4.2: dependencies: - '@types/node': 20.16.12 + '@types/node': 20.16.14 isomorphic-git: 1.27.1 node-object-hash: 3.0.0 typescript: 5.6.3 @@ -6763,13 +6763,13 @@ snapshots: svgo: 3.3.2 vue: 3.5.12(typescript@5.3.3) - vite@5.4.9(@types/node@22.7.6)(less@4.2.0): + vite@5.4.9(@types/node@22.7.8)(less@4.2.0): dependencies: esbuild: 0.21.5 postcss: 8.4.47 rollup: 4.24.0 optionalDependencies: - '@types/node': 22.7.6 + '@types/node': 22.7.8 fsevents: 2.3.3 less: 4.2.0 @@ -6809,9 +6809,9 @@ snapshots: is-plain-object: 3.0.1 vue: 3.5.12(typescript@5.3.3) - vue3-ace-editor@2.2.4(ace-builds@1.36.2)(vue@3.5.12(typescript@5.3.3)): + vue3-ace-editor@2.2.4(ace-builds@1.36.3)(vue@3.5.12(typescript@5.3.3)): dependencies: - ace-builds: 1.36.2 + ace-builds: 1.36.3 resize-observer-polyfill: 1.5.1 vue: 3.5.12(typescript@5.3.3) From 80cb8e11515e3831f3fe3e68888ac10d0d058665 Mon Sep 17 00:00:00 2001 From: Jacky Date: Tue, 22 Oct 2024 23:56:56 +0800 Subject: [PATCH 04/13] docs: update docs regarding to settings v2 --- api/system/install.go | 2 +- docs/.vitepress/config/en.ts | 14 +- docs/.vitepress/config/zh_CN.ts | 20 ++- docs/.vitepress/config/zh_TW.ts | 20 ++- docs/guide/config-app.md | 20 +++ docs/guide/config-cert.md | 43 ++++++ docs/guide/config-database.md | 8 + docs/guide/config-http.md | 18 +++ docs/guide/config-node.md | 16 ++ docs/guide/config-server.md | 109 ++++++++++++-- docs/guide/config-terminal.md | 15 ++ docs/guide/env.md | 119 +++++++++------ docs/zh_CN/guide/config-app.md | 19 +++ docs/zh_CN/guide/config-auth.md | 4 +- docs/zh_CN/guide/config-cert.md | 37 +++++ docs/zh_CN/guide/config-crypto.md | 2 +- docs/zh_CN/guide/config-database.md | 8 + docs/zh_CN/guide/config-http.md | 15 ++ docs/zh_CN/guide/config-node.md | 16 ++ docs/zh_CN/guide/config-server.md | 118 ++++++++++++--- docs/zh_CN/guide/config-terminal.md | 14 ++ docs/zh_CN/guide/env.md | 166 +++++++++++++-------- docs/zh_CN/guide/nginx-ui-template.md | 2 +- docs/zh_TW/guide/config-app.md | 20 +++ docs/zh_TW/guide/config-cert.md | 35 +++++ docs/zh_TW/guide/config-database.md | 8 + docs/zh_TW/guide/config-http.md | 20 +++ docs/zh_TW/guide/config-node.md | 16 ++ docs/zh_TW/guide/config-server.md | 202 ++++++++++++++++++-------- docs/zh_TW/guide/config-terminal.md | 14 ++ docs/zh_TW/guide/env.md | 170 ++++++++++++++-------- go.mod | 20 +-- go.sum | 23 +++ install.sh | 7 +- internal/kernal/boot.go | 2 +- model/model.go | 8 - settings/database.go | 11 ++ settings/server_v1.go | 4 +- settings/settings.go | 2 +- 39 files changed, 1063 insertions(+), 304 deletions(-) create mode 100644 docs/guide/config-app.md create mode 100644 docs/guide/config-cert.md create mode 100644 docs/guide/config-database.md create mode 100644 docs/guide/config-http.md create mode 100644 docs/guide/config-node.md create mode 100644 docs/guide/config-terminal.md create mode 100644 docs/zh_CN/guide/config-app.md create mode 100644 docs/zh_CN/guide/config-cert.md create mode 100644 docs/zh_CN/guide/config-database.md create mode 100644 docs/zh_CN/guide/config-http.md create mode 100644 docs/zh_CN/guide/config-node.md create mode 100644 docs/zh_CN/guide/config-terminal.md create mode 100644 docs/zh_TW/guide/config-app.md create mode 100644 docs/zh_TW/guide/config-cert.md create mode 100644 docs/zh_TW/guide/config-database.md create mode 100644 docs/zh_TW/guide/config-http.md create mode 100644 docs/zh_TW/guide/config-node.md create mode 100644 docs/zh_TW/guide/config-terminal.md create mode 100644 settings/database.go diff --git a/api/system/install.go b/api/system/install.go index 1d86c101..533b39ea 100644 --- a/api/system/install.go +++ b/api/system/install.go @@ -48,7 +48,7 @@ func InstallNginxUI(c *gin.Context) { settings.NodeSettings.Secret = uuid.New().String() settings.CertSettings.Email = json.Email if "" != json.Database { - cSettings.DataBaseSettings.Name = json.Database + settings.DatabaseSettings.Name = json.Database } err := settings.Save() diff --git a/docs/.vitepress/config/en.ts b/docs/.vitepress/config/en.ts index bde49db0..4aac1e85 100644 --- a/docs/.vitepress/config/en.ts +++ b/docs/.vitepress/config/en.ts @@ -34,14 +34,20 @@ export const enConfig: LocaleSpecificConfig = { text: 'Configuration', collapsed: false, items: [ + {text: 'App', link: '/guide/config-app'}, {text: 'Server', link: '/guide/config-server'}, - {text: 'Nginx', link: '/guide/config-nginx'}, - {text: 'Open AI', link: '/guide/config-openai'}, + {text: 'Database', link: '/guide/config-database'}, + {text: 'Auth', link: '/guide/config-auth'}, {text: 'Casdoor', link: '/guide/config-casdoor'}, - {text: 'Logrotate', link: '/guide/config-logrotate'}, + {text: 'Cert', link: '/guide/config-cert'}, {text: 'Cluster', link: '/guide/config-cluster'}, - {text: 'Auth', link: '/guide/config-auth'}, {text: 'Crypto', link: '/guide/config-crypto'}, + {text: 'Http', link: '/guide/config-http'}, + {text: 'Logrotate', link: '/guide/config-logrotate'}, + {text: 'Nginx', link: '/guide/config-nginx'}, + {text: 'Node', link: '/guide/config-node'}, + {text: 'Open AI', link: '/guide/config-openai'}, + {text: 'Terminal', link: '/guide/config-terminal'}, {text: 'Webauthn', link: '/guide/config-webauthn'} ] }, diff --git a/docs/.vitepress/config/zh_CN.ts b/docs/.vitepress/config/zh_CN.ts index 9fb01ebe..392e8772 100644 --- a/docs/.vitepress/config/zh_CN.ts +++ b/docs/.vitepress/config/zh_CN.ts @@ -39,15 +39,21 @@ export const zhCNConfig: LocaleSpecificConfig = { text: '配置', collapsed: false, items: [ - {text: '服务端', link: '/zh_CN/guide/config-server'}, - {text: 'Nginx', link: '/zh_CN/guide/config-nginx'}, - {text: 'Open AI', link: '/zh_CN/guide/config-openai'}, + {text: 'App', link: '/zh_CN/guide/config-app'}, + {text: 'Server', link: '/zh_CN/guide/config-server'}, + {text: 'Database', link: '/zh_CN/guide/config-database'}, + {text: 'Auth', link: '/zh_CN/guide/config-auth'}, {text: 'Casdoor', link: '/zh_CN/guide/config-casdoor'}, + {text: 'Cert', link: '/zh_CN/guide/config-cert'}, + {text: 'Cluster', link: '/zh_CN/guide/config-cluster'}, + {text: 'Crypto', link: '/zh_CN/guide/config-crypto'}, + {text: 'Http', link: '/zh_CN/guide/config-http'}, {text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'}, - {text: '集群', link: '/zh_CN/guide/config-cluster'}, - {text: '认证', link: '/zh_CN/guide/config-auth'}, - {text: '加密', link: '/zh_CN/guide/config-crypto'}, - {text: 'Webauthn', link: '/zh_CN/guide/config-webauthn'}, + {text: 'Nginx', link: '/zh_CN/guide/config-nginx'}, + {text: 'Node', link: '/zh_CN/guide/config-node'}, + {text: 'Open AI', link: '/zh_CN/guide/config-openai'}, + {text: 'Terminal', link: '/zh_CN/guide/config-terminal'}, + {text: 'Webauthn', link: '/zh_CN/guide/config-webauthn'} ] }, { diff --git a/docs/.vitepress/config/zh_TW.ts b/docs/.vitepress/config/zh_TW.ts index 15dc1216..7b44d2b5 100644 --- a/docs/.vitepress/config/zh_TW.ts +++ b/docs/.vitepress/config/zh_TW.ts @@ -39,15 +39,21 @@ export const zhTWConfig: LocaleSpecificConfig = { text: '配置', collapsed: false, items: [ - {text: '服務端', link: '/zh_TW/guide/config-server'}, - {text: 'Nginx', link: '/zh_TW/guide/config-nginx'}, - {text: 'Open AI', link: '/zh_TW/guide/config-openai'}, + {text: 'App', link: '/zh_TW/guide/config-app'}, + {text: 'Server', link: '/zh_TW/guide/config-server'}, + {text: 'Database', link: '/zh_TW/guide/config-database'}, + {text: 'Auth', link: '/zh_TW/guide/config-auth'}, {text: 'Casdoor', link: '/zh_TW/guide/config-casdoor'}, + {text: 'Cert', link: '/zh_TW/guide/config-cert'}, + {text: 'Cluster', link: '/zh_TW/guide/config-cluster'}, + {text: 'Crypto', link: '/zh_TW/guide/config-crypto'}, + {text: 'Http', link: '/zh_TW/guide/config-http'}, {text: 'Logrotate', link: '/zh_TW/guide/config-logrotate'}, - {text: '集群', link: '/zh_TW/guide/config-cluster'}, - {text: '認證', link: '/zh_TW/guide/config-auth'}, - {text: '加密', link: '/zh_TW/guide/config-crypto'}, - {text: 'Webauthn', link: '/zh_TW/guide/config-webauthn'}, + {text: 'Nginx', link: '/zh_TW/guide/config-nginx'}, + {text: 'Node', link: '/zh_TW/guide/config-node'}, + {text: 'Open AI', link: '/zh_TW/guide/config-openai'}, + {text: 'Terminal', link: '/zh_TW/guide/config-terminal'}, + {text: 'Webauthn', link: '/zh_TW/guide/config-webauthn'} ] }, { diff --git a/docs/guide/config-app.md b/docs/guide/config-app.md new file mode 100644 index 00000000..8a2d78c4 --- /dev/null +++ b/docs/guide/config-app.md @@ -0,0 +1,20 @@ +# App + +## PageSize + +- Type: `int` +- Default: 10 +- Version: `>=v2.0.0-beta.37` + +This option is used to set the page size of list pagination in the Nginx UI. Adjusting the page size can help in +managing large amounts of data more effectively, but a too large number can increase the load on the server. + +## JwtSecret +- Type: `string` +- Version: `>=v2.0.0-beta.37` + +This option is used to configure the key used by the Nginx UI server to generate JWT. + +JWT is a standard for verifying user identity. It can generate a token after the user logs in, and then use the token to verify the user's identity in subsequent requests. + +If you use the one-click installation script to deploy Nginx UI, the script will generate a UUID value and set it as the value of this option. diff --git a/docs/guide/config-cert.md b/docs/guide/config-cert.md new file mode 100644 index 00000000..bec0918e --- /dev/null +++ b/docs/guide/config-cert.md @@ -0,0 +1,43 @@ +# Cert + +## CADir +- Type: `string` +- Version:`>= v2.0.0-beta.37` + +When applying for a Let's Encrypt certificate, we use the default CA address of Let's Encrypt. If you need to debug or +obtain certificates from other providers, you can set CADir to their address. + +::: tip +Please note that the address provided by +CADir needs to comply with the `RFC 8555` standard. +::: + +## RecursiveNameservers + +- Version:`>= v2.0.0-beta.37` +- Type: `[]string` +- Example: `8.8.8.8:53,1.1.1.1:53` + +This option is used to set the recursive nameservers used by +Nginx UI in the DNS challenge step of applying for a certificate. +If this option is not configured, Nginx UI will use the nameservers settings of the operating system. + + +## CertRenewalInterval + +- Version:`>= v2.0.0-beta.37` +- Type: `int` +- Default value: `7` + +This option is used to set the automatic renewal interval of the Let's Encrypt certificate. +By default, Nginx UI will automatically renew the certificate every 7 days. + +## HTTPChallengePort + +- Version:`>= v2.0.0-beta.37` +- Type: `int` +- Default: `9180` + +This option is used to set the port for backend listening in the HTTP01 challenge mode when obtaining Let's Encrypt +certificates. The HTTP01 challenge is a domain validation method used by Let's Encrypt to verify that you control the +domain for which you're requesting a certificate. diff --git a/docs/guide/config-database.md b/docs/guide/config-database.md new file mode 100644 index 00000000..7f491ec3 --- /dev/null +++ b/docs/guide/config-database.md @@ -0,0 +1,8 @@ +# Database + +## Name +- Type: `string` +- Default: `database` +- Version: `>=v2.0.0-beta.37` + +This option is used to set the name of the sqlite database used by Nginx UI to store its data. diff --git a/docs/guide/config-http.md b/docs/guide/config-http.md new file mode 100644 index 00000000..cff39d61 --- /dev/null +++ b/docs/guide/config-http.md @@ -0,0 +1,18 @@ +# Http + +## GithubProxy + +- Type: `string` +- Version: `>= v2.0.0-beta.37` +- Suggestion: `https://mirror.ghproxy.com/` + +For users who may experience difficulties downloading resources from GitHub (such as in mainland China), this option +allows them to set a proxy for github.com to improve accessibility. + +## InsecureSkipVerify + +- Version:`>= v2.0.0-beta.37` +- Type: `bool` + +This option is used to skip the verification of the certificate of servers when Nginx UI sends requests to them. + diff --git a/docs/guide/config-node.md b/docs/guide/config-node.md new file mode 100644 index 00000000..2110f863 --- /dev/null +++ b/docs/guide/config-node.md @@ -0,0 +1,16 @@ +# Node + +## Name + +- Version:`>= v2.0.0-beta.37` +- Type: `string` + +Use this option to customize the name of local server to be displayed in the environment indicator. + + +## Secret +- Type: `string` +- Version: `>= v2.0.0-beta.37` + +This secret is used to authenticate the communication between the Nginx UI servers. +Also, you can use this secret to access the Nginx UI API without a password. diff --git a/docs/guide/config-server.md b/docs/guide/config-server.md index 0097f5e9..94e13a86 100644 --- a/docs/guide/config-server.md +++ b/docs/guide/config-server.md @@ -3,19 +3,20 @@ The server section of the Nginx UI configuration deals with various settings that control the behavior and operation of the Nginx UI server. In this section, we will discuss the available options, their default values, and their purpose. -## HttpHost +## Host - Type: `string` +- Version: `>= v2.0.0-beta.37` - Default:`0.0.0.0` The hostname on which the Nginx UI server listens for incoming HTTP requests. Changing the default hostname can be useful for improving the security of Nginx UI. -## HttpPort - -- Type: `int` +## Port +- Type: `uint` +- Version: `>= v2.0.0-beta.37` - Default: `9000` -Nginx UI server listen port. This option is used to configure the port on which the Nginx UI server listens for incoming +This option is used to configure the port on which the Nginx UI server listens for incoming HTTP requests. Changing the default port can be useful for avoiding port conflicts or enhancing security. ## RunMode @@ -32,20 +33,62 @@ When using the `debug` mode, Nginx UI will print SQL and its execution time and When using the `release` mode, Nginx UI will not print the execution time and caller of SQL on the console, and only the log of `Info` level or higher will be printed. +## HttpHost +- Type: `string` +- Default:`0.0.0.0` + +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Host` instead. +::: + +The hostname on which the Nginx UI server listens for incoming HTTP requests. +Changing the default hostname can be useful for improving the security of Nginx UI. + +## HttpPort +- Type: `int` +- Default: `9000` + +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Port` instead. +::: + +This option is used to configure the port on which the Nginx UI server listens for incoming +HTTP requests. Changing the default port can be useful for avoiding port conflicts or enhancing security. + + ## JwtSecret - Type: `string` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `App.JwtSecret` instead. +::: + This option is used to configure the key used by the Nginx UI server to generate JWT. JWT is a standard for verifying user identity. It can generate a token after the user logs in, and then use the token to verify the user's identity in subsequent requests. If you use the one-click installation script to deploy Nginx UI, the script will generate a UUID value and set it as the value of this option. +## NodeSecret +- Type: `string` +- Version: `>= v2.0.0-beta.24, <= 2.0.0-beta.36` + +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Node.Secret` instead. +::: + +This secret is used to authenticate the communication between the Nginx UI servers. +Also, you can use this secret to access the Nginx UI API without a password. + ## HTTPChallengePort - Type: `int` - Default: `9180` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Cert.HTTPChallengePort` instead. +::: + This option is used to set the port for backend listening in the HTTP01 challenge mode when obtaining Let's Encrypt certificates. The HTTP01 challenge is a domain validation method used by Let's Encrypt to verify that you control the domain for which you're requesting a certificate. @@ -53,6 +96,10 @@ domain for which you're requesting a certificate. ## Email - Type: `string` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Cert.Email` instead. +::: + When obtaining a Let's Encrypt certificate, this option is used to set your email address. Let's Encrypt will use your email address to notify you of the expiration date of your certificate. @@ -61,6 +108,10 @@ Let's Encrypt will use your email address to notify you of the expiration date o - Type: `string` - Default: `database` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Database.Name` instead. +::: + This option is used to set the name of the sqlite database used by Nginx UI to store its data. ## StartCmd @@ -68,6 +119,10 @@ This option is used to set the name of the sqlite database used by Nginx UI to s - Type: `string` - Default: `login` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Terminal.StartCmd` instead. +::: + This option is used to set the start command of the web terminal. ::: warning @@ -81,6 +136,10 @@ terminal, please set it to `bash` or `zsh` (if installed). - Type: `int` - Default: 10 +::: warning +Deprecated in `v2.0.0-beta.37`, please use `App.PageSize` instead. +::: + This option is used to set the page size of list pagination in the Nginx UI. Adjusting the page size can help in managing large amounts of data more effectively, but a too large number can increase the load on the server. @@ -88,6 +147,10 @@ managing large amounts of data more effectively, but a too large number can incr - Type: `string` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Cert.CADir` instead. +::: + When applying for a Let's Encrypt certificate, we use the default CA address of Let's Encrypt. If you need to debug or obtain certificates from other providers, you can set CADir to their address. @@ -101,37 +164,53 @@ CADir needs to comply with the `RFC 8555` standard. - Type: `string` - Suggestion: `https://mirror.ghproxy.com/` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Http.GithubProxy` instead. +::: + For users who may experience difficulties downloading resources from GitHub (such as in mainland China), this option allows them to set a proxy for github.com to improve accessibility. ## CertRenewalInterval -- Version:`>= v2.0.0-beta.22` +- Version:`>= v2.0.0-beta.22, <= 2.0.0-beta.36` - Type: `int` - Default value: `7` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Cert.CertRenewalInterval` instead. +::: + This option is used to set the automatic renewal interval of the Let's Encrypt certificate. By default, Nginx UI will automatically renew the certificate every 7 days. ## RecursiveNameservers -- Version:`>= v2.0.0-beta.22` +- Version:`>= v2.0.0-beta.22, <= 2.0.0-beta.36` - Type: `[]string` - Example: `8.8.8.8:53,1.1.1.1:53` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Cert.RecursiveNameservers` instead. +::: + This option is used to set the recursive nameservers used by Nginx UI in the DNS challenge step of applying for a certificate. If this option is not configured, Nginx UI will use the nameservers settings of the operating system. ## SkipInstallation -- Version:`>= v2.0.0-beta.23` +- Version:`>= v2.0.0-beta.23, <= 2.0.0-beta.36` - Type: `bool` - Default value: `false` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Node.SkipInstallation` instead. +::: + You can skip the installation of the Nginx UI server by setting this option to `true`. This is useful when you want to deploy Nginx UI to multiple servers with -a same configuration file or environment variables. +the same configuration file or environment variables. By default, if you enabled the skip installation mode without setting the `JWTSecret` and `NodeSecret` options in the server section, Nginx UI will generate a random UUID value for these two options. @@ -141,14 +220,22 @@ Nginx UI will not create a system initial acme user, this means you can't apply ## Name -- Version:`>= v2.0.0-beta.23` +- Version:`>= v2.0.0-beta.23, <= 2.0.0-beta.36` - Type: `string` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Http.InsecureSkipVerify` instead. +::: + Use this option to customize the name of local server to be displayed in the environment indicator. ## InsecureSkipVerify -- Version:`>= v2.0.0-beta.30` +- Version:`>= v2.0.0-beta.30, <= 2.0.0-beta.36` - Type: `bool` +::: warning +Deprecated in `v2.0.0-beta.37`, please use `Http.InsecureSkipVerify` instead. +::: + This option is used to skip the verification of the certificate of servers when Nginx UI sends requests to them. diff --git a/docs/guide/config-terminal.md b/docs/guide/config-terminal.md new file mode 100644 index 00000000..6bcd4229 --- /dev/null +++ b/docs/guide/config-terminal.md @@ -0,0 +1,15 @@ +# Terminal + +## StartCmd + +- Type: `string` +- Default: `login` +- Version: `>= v2.0.0-beta.37` + +This option is used to set the start command of the web terminal. + +::: warning +For security reason, we use `login` as the start command, so you have to log in via the default authentication method of +the Linux. If you don't want to enter your username and password for verification every time you access the web +terminal, please set it to `bash` or `zsh` (if installed). +::: diff --git a/docs/guide/env.md b/docs/guide/env.md index 4c177270..8b831ceb 100644 --- a/docs/guide/env.md +++ b/docs/guide/env.md @@ -1,53 +1,34 @@ # Environment Variables -Applicable for version v2.0.0-beta.23 and above. +Applicable for version v2.0.0-beta.37 and above. + +## App +| Configuration Setting | Environment Variable | +|-----------------------|-------------------------| +| PageSize | NGINX_UI_APP_PAGE_SIZE | +| JwtSecret | NGINX_UI_APP_JWT_SECRET | -## Server +## Server | Configuration Setting | Environment Variable | |-----------------------|---------------------------------------| -| HttpPort | NGINX_UI_SERVER_HTTP_PORT | +| Host | NGINX_UI_SERVER_HOST | +| Port | NGINX_UI_SERVER_PORT | | RunMode | NGINX_UI_SERVER_RUN_MODE | -| JwtSecret | NGINX_UI_SERVER_JWT_SECRET | -| HTTPChallengePort | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT | -| StartCmd | NGINX_UI_SERVER_START_CMD | -| Database | NGINX_UI_SERVER_DATABASE | -| CADir | NGINX_UI_SERVER_CA_DIR | -| GithubProxy | NGINX_UI_SERVER_GITHUB_PROXY | -| NodeSecret | NGINX_UI_SERVER_NODE_SECRET | -| Demo | NGINX_UI_SERVER_DEMO | -| PageSize | NGINX_UI_SERVER_PAGE_SIZE | -| HttpHost | NGINX_UI_SERVER_HTTP_HOST | -| CertRenewalInterval | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL | -| RecursiveNameservers | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS | -| SkipInstallation | NGINX_UI_SERVER_SKIP_INSTALLATION | -| Name | NGINX_UI_SERVER_NAME | -| InsecureSkipVerify | NGINX_UI_SERVER_INSECURE_SKIP_VERIFY | - -## Nginx - -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------------| -| AccessLogPath | NGINX_UI_NGINX_ACCESS_LOG_PATH | -| ErrorLogPath | NGINX_UI_NGINX_ERROR_LOG_PATH | -| ConfigDir | NGINX_UI_NGINX_CONFIG_DIR | -| PIDPath | NGINX_UI_NGINX_PID_PATH | -| TestConfigCmd | NGINX_UI_NGINX_TEST_CONFIG_CMD | -| ReloadCmd | NGINX_UI_NGINX_RELOAD_CMD | -| RestartCmd | NGINX_UI_NGINX_RESTART_CMD | -| LogDirWhiteList | NGINX_UI_NGINX_LOG_DIR_WHITE_LIST | -## OpenAI +## Database +| Configuration Setting | Environment Variable | +|-----------------------|----------------------| +| Name | NGINX_UI_DB_NAME | -| Configuration Setting | Environment Variable | -|-----------------------|--------------------------| -| Model | NGINX_UI_OPENAI_MODEL | -| BaseUrl | NGINX_UI_OPENAI_BASE_URL | -| Proxy | NGINX_UI_OPENAI_PROXY | -| Token | NGINX_UI_OPENAI_TOKEN | +## Auth +| Configuration Setting | Environment Variable | +|-----------------------|-------------------------------------| +| IPWhiteList | NGINX_UI_AUTH_IP_WHITE_LIST | +| BanThresholdMinutes | NGINX_UI_AUTH_BAN_THRESHOLD_MINUTES | +| MaxAttempts | NGINX_UI_AUTH_MAX_ATTEMPTS | ## Casdoor - | Configuration Setting | Environment Variable | |-----------------------|-----------------------------------| | Endpoint | NGINX_UI_CASDOOR_ENDPOINT | @@ -58,19 +39,69 @@ Applicable for version v2.0.0-beta.23 and above. | Application | NGINX_UI_CASDOOR_APPLICATION | | RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI | -## Logrotate +## Cert +| Configuration Setting | Environment Variable | +|-----------------------|-------------------------------------| +| Email | NGINX_UI_CERT_EMAIL | +| CADir | NGINX_UI_CERT_CA_DIR | +| RenewalInterval | NGINX_UI_CERT_RENEWAL_INTERVAL | +| RecursiveNameservers | NGINX_UI_CERT_RECURSIVE_NAMESERVERS | +| HTTPChallengePort | NGINX_UI_CERT_HTTP_CHALLENGE_PORT | + +## Cluster +| Configuration Setting | Environment Variable | +|-----------------------|-----------------------| +| Node | NGINX_UI_CLUSTER_NODE | + +## Crypto +| Configuration Setting | Environment Variable | +|-----------------------|-------------------------| +| Secret | NGINX_UI_CRYPTO_SECRET | + +## Http +| Configuration Setting | Environment Variable | +|-----------------------|------------------------------------| +| GithubProxy | NGINX_UI_HTTP_GITHUB_PROXY | +| InsecureSkipVerify | NGINX_UI_HTTP_INSECURE_SKIP_VERIFY | +## Logrotate | Configuration Setting | Environment Variable | |-----------------------|-----------------------------| | Enabled | NGINX_UI_LOGROTATE_ENABLED | | CMD | NGINX_UI_LOGROTATE_CMD | | Interval | NGINX_UI_LOGROTATE_INTERVAL | -## Auth +## Nginx +| Configuration Setting | Environment Variable | +|-----------------------|-----------------------------------| +| AccessLogPath | NGINX_UI_NGINX_ACCESS_LOG_PATH | +| ErrorLogPath | NGINX_UI_NGINX_ERROR_LOG_PATH | +| ConfigDir | NGINX_UI_NGINX_CONFIG_DIR | +| PIDPath | NGINX_UI_NGINX_PID_PATH | +| TestConfigCmd | NGINX_UI_NGINX_TEST_CONFIG_CMD | +| ReloadCmd | NGINX_UI_NGINX_RELOAD_CMD | +| RestartCmd | NGINX_UI_NGINX_RESTART_CMD | +| LogDirWhiteList | NGINX_UI_NGINX_LOG_DIR_WHITE_LIST | + +## Node +| Configuration Setting | Environment Variable | +|-----------------------|---------------------------------| +| Name | NGINX_UI_NODE_NAME | +| Secret | NGINX_UI_NODE_SECRET | +| SkipInstallation | NGINX_UI_NODE_SKIP_INSTALLATION | + +## OpenAI +| Configuration Setting | Environment Variable | +|-----------------------|--------------------------| +| Model | NGINX_UI_OPENAI_MODEL | +| BaseUrl | NGINX_UI_OPENAI_BASE_URL | +| Proxy | NGINX_UI_OPENAI_PROXY | +| Token | NGINX_UI_OPENAI_TOKEN | -| Configuration Setting | Environment Variable | -|-----------------------|---------------------------| -| IPWhiteList | NGINX_UI_AUTH_IPWhiteList | +## Terminal +| Configuration Setting | Environment Variable | +|-----------------------|-------------------------------------| +| StartCmd | NGINX_UI_TERMINAL_START_CMD | ## Webauthn diff --git a/docs/zh_CN/guide/config-app.md b/docs/zh_CN/guide/config-app.md new file mode 100644 index 00000000..b4c86238 --- /dev/null +++ b/docs/zh_CN/guide/config-app.md @@ -0,0 +1,19 @@ +# App + +## PageSize + +- 类型: `int` +- 默认值: 10 +- 版本: `>=v2.0.0-beta.37` + +此选项用于设置 Nginx UI 中列表分页的页面大小。调整页面大小可以更有效地管理大量数据,但过大的数字会增加服务器的负载。 + +## JwtSecret +- 类型: `string` +- 版本: `>=v2.0.0-beta.37` + +此选项用于配置 Nginx UI 服务器生成 JWT 的密钥。 + +JWT 是一种验证用户身份的标准。用户登录后可以生成一个令牌,然后在后续请求中使用该令牌验证用户身份。 + +如果您使用一键安装脚本部署 Nginx UI,脚本将生成一个 UUID 值并将其设置为此选项的值。 diff --git a/docs/zh_CN/guide/config-auth.md b/docs/zh_CN/guide/config-auth.md index 742da0d0..be815cc5 100644 --- a/docs/zh_CN/guide/config-auth.md +++ b/docs/zh_CN/guide/config-auth.md @@ -19,12 +19,12 @@ IPWhiteList = 2001:0000:130F:0000:0000:09C0:876A:130B ## BanThresholdMinutes - Type: `int` -- Default: `10` +- 默认值:`10` 默认情况下,如果用户在 10 分钟内登录失败 10 次,用户将被禁止登录 10 分钟。 ## MaxAttempts - Type: `int` -- Default: `10` +- 默认值:`10` 默认情况下,用户可以在 10 分钟内尝试登录 10 次。 diff --git a/docs/zh_CN/guide/config-cert.md b/docs/zh_CN/guide/config-cert.md new file mode 100644 index 00000000..f0940446 --- /dev/null +++ b/docs/zh_CN/guide/config-cert.md @@ -0,0 +1,37 @@ +# Cert + +## CADir +- 类型: `string` +- 版本:`>= v2.0.0-beta.37` + +在申请 Let's Encrypt 证书时,我们使用 Let's Encrypt 的默认 CA 地址。 +如果您需要调试或从其他提供商获取证书,您可以将 CADir 设置为他们的地址。 + +::: tip 提示 +请注意,CADir 提供的地址需要符合 `RFC 8555` 标准。 +::: + +## RecursiveNameservers + +- 版本:`>= v2.0.0-beta.37` +- 类型: `[]string` +- 示例: `8.8.8.8:53,1.1.1.1:53` + +此选项用于设置 Nginx UI 在申请证书的 DNS 挑战步骤所使用的递归域名服务器。在不配置此项目的情况下,Nginx UI 使用操作系统的域名服务器设置。 + +## CertRenewalInterval + +- 版本:`>= v2.0.0-beta.37` +- 类型: `int` +- 默认值: `7` + +此选项用于设置 Let's Encrypt 证书的自动续签间隔。默认情况下,Nginx UI 每隔 7 天会自动续签证书。 + +## HTTPChallengePort + +- 版本:`>= v2.0.0-beta.37` +- 类型: `int` +- 默认值: `9180` + +在获取 Let's Encrypt 证书时,此选项用于在 HTTP01 挑战模式中设置后端监听端口。 +HTTP01 挑战是 Let's Encrypt 用于验证您控制请求证书的域的域验证方法。 diff --git a/docs/zh_CN/guide/config-crypto.md b/docs/zh_CN/guide/config-crypto.md index 146f61ed..1ad28ae9 100644 --- a/docs/zh_CN/guide/config-crypto.md +++ b/docs/zh_CN/guide/config-crypto.md @@ -1,6 +1,6 @@ # Crypto ## Secret -- Type: `string` +- 类型: `string` 如果这个值为空,Nginx UI 将会自动生成一个随机的密钥。这个密钥用于加密存储在数据库中的敏感数据。 diff --git a/docs/zh_CN/guide/config-database.md b/docs/zh_CN/guide/config-database.md new file mode 100644 index 00000000..381810c4 --- /dev/null +++ b/docs/zh_CN/guide/config-database.md @@ -0,0 +1,8 @@ +# Database + +## Name +- 类型: `string` +- 默认值: `database` +- 版本: `>=v2.0.0-beta.37` + +此选项用于设置 Nginx UI 用于存储其数据的 sqlite 数据库的名称。 diff --git a/docs/zh_CN/guide/config-http.md b/docs/zh_CN/guide/config-http.md new file mode 100644 index 00000000..29763935 --- /dev/null +++ b/docs/zh_CN/guide/config-http.md @@ -0,0 +1,15 @@ +# Http + +## GithubProxy +- 版本: `>= v2.0.0-beta.37` +- 类型:`string` +- 建议:`https://mirror.ghproxy.com/` + +- 对于可能在从 Github 下载资源时遇到困难的用户(如在中国大陆),此选项允许他们为 github.com 设置代理,以提高可访问性。 + +## InsecureSkipVerify + +- 版本:`>= v2.0.0-beta.37` +- 类型: `bool` + +此选项用于配置 Nginx UI 服务器在与其他服务器建立 TLS 连接时是否跳过证书验证。 diff --git a/docs/zh_CN/guide/config-node.md b/docs/zh_CN/guide/config-node.md new file mode 100644 index 00000000..3639244b --- /dev/null +++ b/docs/zh_CN/guide/config-node.md @@ -0,0 +1,16 @@ +# Node + +## Name + +- 版本:`>= v2.0.0-beta.37` +- 类型:`string` + +使用此选项自定义本地服务器的名称,以在环境指示器中显示。 + + +## Secret +- 类型: `string` +- 版本: `>= v2.0.0-beta.37` + +此密钥用于验证 Nginx UI 服务器之间的通信。 +此外,您可以使用此密钥在不使用密码的情况下访问 Nginx UI API。 diff --git a/docs/zh_CN/guide/config-server.md b/docs/zh_CN/guide/config-server.md index 37e5327b..950ff1be 100644 --- a/docs/zh_CN/guide/config-server.md +++ b/docs/zh_CN/guide/config-server.md @@ -1,19 +1,20 @@ -# 服务端 +# Server Nginx UI 配置的服务端部分涉及控制 Nginx UI 服务器的各种设置。在页面中,我们将讨论可用的选项、它们的默认值以及它们的目的。 -## HttpHost +## Host - 类型: `string` -- 默认值:`0.0.0.0` +- 版本: `>= v2.0.0-beta.37` +- Default:`0.0.0.0` Nginx UI 服务器监听的主机名。此选项用于配置 Nginx UI 服务器监听传入 HTTP 请求的主机名。 更改默认主机名可能有助于提升安全性。 -## HttpPort - -- 类型:`int` +## Port +- Type: `uint` +- 版本: `>= v2.0.0-beta.37` - 默认值:`9000` -Nginx UI 服务器监听端口。此选项用于配置 Nginx UI 服务器监听传入 HTTP 请求的端口。更改默认端口对于避免端口冲突或增强安全性可能很有用。 +此选项用于配置 Nginx UI 服务器监听传入 HTTP 请求的端口。更改默认端口对于避免端口冲突或增强安全性可能很有用。 ## RunMode @@ -29,8 +30,32 @@ Nginx UI 的日志分为 6 个级别,分别为 `Debug`、`Info`、`Warn`、`Er 当使用 `release` 模式时,Nginx UI 将不会在控制台打印 SQL 的执行时间和调用者, 只有 `Info` 级别或更高等级的日志才会被打印。 +## HttpHost +- 类型: `string` +- Default:`0.0.0.0` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Host` 替代。 +::: + +Nginx UI 服务器监听的主机名。此选项用于配置 Nginx UI 服务器监听传入 HTTP 请求的主机名。 更改默认主机名可能有助于提升安全性。 + +## HttpPort +- Type: `int` +- 默认值:`9000` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Port` 替代。 +::: + +此选项用于配置 Nginx UI 服务器监听传入 HTTP 请求的端口。更改默认端口对于避免端口冲突或增强安全性可能很有用。 + ## JwtSecret -- 类型:`string` +- 类型: `string` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `App.JwtSecret` 替代。 +::: 此选项用于配置 Nginx UI 服务器用于生成 JWT 的密钥。 @@ -38,17 +63,36 @@ JWT 是一种用于验证用户身份的标准,它可以在用户登录后生 如果您使用一键安装脚本来部署 Nginx UI,脚本将会生成一个 UUID 值并将它设置为此选项的值。 +## NodeSecret +- 类型: `string` +- 版本: `>= v2.0.0-beta.24, <= 2.0.0-beta.36` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Node.Secret` 替代。 +::: + +此密钥用于验证 Nginx UI 服务器之间的通信。 +此外,您可以使用此密钥在不使用密码的情况下访问 Nginx UI API。 + ## HTTPChallengePort - 类型:`int` - 默认值:`9180` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Cert.HTTPChallengePort` 替代。 +::: + 在获取 Let's Encrypt 证书时,此选项用于在 HTTP01 挑战模式中设置后端监听端口。HTTP01 挑战是 Let's Encrypt 用于验证您控制请求证书的域的域验证方法。 ## Email - 类型:`string` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Cert.Email` 替代。 +::: + 在获取 Let's Encrypt 证书时,此选项用于设置您的电子邮件地址。Let's Encrypt 会将您的电子邮件地址用于通知您证书的到期时间。 ## Database @@ -56,6 +100,10 @@ JWT 是一种用于验证用户身份的标准,它可以在用户登录后生 - 类型:`string` - 默认值:`database` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Database.Name` 替代。 +::: + 此选项用于设置 Nginx UI 用于存储其数据的 sqlite 数据库的名称。 ## StartCmd @@ -63,6 +111,10 @@ JWT 是一种用于验证用户身份的标准,它可以在用户登录后生 - 类型:`string` - 默认值:`login` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Terminal.StartCmd` 替代。 +::: + 此选项用于设置 Web 终端的启动命令。 ::: warning 警告 @@ -75,11 +127,19 @@ JWT 是一种用于验证用户身份的标准,它可以在用户登录后生 - 类型:`int` - 默认值:`10` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `App.PageSize` 替代。 +::: + 此选项用于设置 Nginx UI 中列表分页的页面大小。调整页面大小有助于更有效地管理大量数据,但是过大的数量可能会增加服务器的压力。 ## CADir -- 类型:`string` +- 类型: `string` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Cert.CADir` 替代。 +::: 在申请 Let's Encrypt 证书时,我们使用 Let's Encrypt 的默认 CA 地址。如果您需要调试或从其他提供商获取证书,您可以将 CADir 设置为他们的地址。 @@ -93,29 +153,45 @@ JWT 是一种用于验证用户身份的标准,它可以在用户登录后生 - 类型:`string` - 建议:`https://mirror.ghproxy.com/` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Http.GithubProxy` 替代。 +::: + 对于可能在从 Github 下载资源时遇到困难的用户(如在中国大陆),此选项允许他们为 github.com 设置代理,以提高可访问性。 ## CertRenewalInterval -- 版本:`>= v2.0.0-beta.22` +- 版本:`>= v2.0.0-beta.22, <= 2.0.0-beta.36` - 类型:`int` - 默认值: `7` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Cert.CertRenewalInterval` 替代。 +::: + 此选项用于设置 Let's Encrypt 证书的自动续签间隔。默认情况下,Nginx UI 每隔 7 天会自动续签证书。 ## RecursiveNameservers -- 版本:`>= v2.0.0-beta.22` +- 版本:`>= v2.0.0-beta.22, <= 2.0.0-beta.36` - 类型: `[]string` - 示例: `8.8.8.8:53,1.1.1.1:53` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Cert.RecursiveNameservers` 替代。 +::: + 此选项用于设置 Nginx UI 在申请证书的 DNS 挑战步骤所使用的递归域名服务器。在不配置此项目的情况下,Nginx UI 使用操作系统的域名服务器设置。 ## SkipInstallation -- 版本:`>= v2.0.0-beta.23` -- 类型:`bool` -- 默认值:`false` +- 版本:`>= v2.0.0-beta.23, <= 2.0.0-beta.36` +- 类型: `bool` +- 默认值: `false` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Node.SkipInstallation` 替代。 +::: 通过将此选项设置为 `true`,您可以跳过 Nginx UI 服务器的安装。 当您希望使用相同的配置文件或环境变量将 Nginx UI 部署到多个服务器时,这非常有用。 @@ -128,14 +204,22 @@ Nginx UI 将不会创建系统初始的 acme 用户,这意味着您无法在 ## Name -- 版本:`>= v2.0.0-beta.23` -- 类型:`string` +- 版本:`>= v2.0.0-beta.23, <= 2.0.0-beta.36` +- 类型: `string` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Http.InsecureSkipVerify` 替代。 +::: 使用此选项自定义本地服务器的名称,以在环境指示器中显示。 ## InsecureSkipVerify -- 版本:`>= v2.0.0-beta.30` +- 版本:`>= v2.0.0-beta.30, <= 2.0.0-beta.36` - 类型: `bool` +::: warning 警告 +已在 `v2.0.0-beta.37` 中废弃,请使用 `Http.InsecureSkipVerify` 替代。 +::: + 此选项用于配置 Nginx UI 服务器在与其他服务器建立 TLS 连接时是否跳过证书验证。 diff --git a/docs/zh_CN/guide/config-terminal.md b/docs/zh_CN/guide/config-terminal.md new file mode 100644 index 00000000..f75cc5ef --- /dev/null +++ b/docs/zh_CN/guide/config-terminal.md @@ -0,0 +1,14 @@ +# Terminal + +## StartCmd + +- 类型: `string` +- 默认值: `login` +- 版本: `>= v2.0.0-beta.37` + +此选项用于设置 Web 终端的启动命令。 + +::: warning 警告 +出于安全原因,我们将启动命令设置为 `login`,因此您必须通过 Linux 的默认身份验证方法登录。 +如果您不想每次访问 Web 终端时都输入用户名和密码进行验证,请将其设置为 `bash` 或 `zsh`(如果已安装)。 +::: diff --git a/docs/zh_CN/guide/env.md b/docs/zh_CN/guide/env.md index 649aed89..93f5bb47 100644 --- a/docs/zh_CN/guide/env.md +++ b/docs/zh_CN/guide/env.md @@ -1,84 +1,128 @@ # 环境变量 -适用于 v2.0.0-beta.23 及以上版本 +适用于 v2.0.0-beta.37 及以上版本。 + +## App + +| 配置 | 环境变量 | +|-----------|-------------------------| +| PageSize | NGINX_UI_APP_PAGE_SIZE | +| JwtSecret | NGINX_UI_APP_JWT_SECRET | ## Server -| Configuration Setting | Environment Variable | -|-----------------------|---------------------------------------| -| HttpPort | NGINX_UI_SERVER_HTTP_PORT | -| RunMode | NGINX_UI_SERVER_RUN_MODE | -| JwtSecret | NGINX_UI_SERVER_JWT_SECRET | -| HTTPChallengePort | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT | -| StartCmd | NGINX_UI_SERVER_START_CMD | -| Database | NGINX_UI_SERVER_DATABASE | -| CADir | NGINX_UI_SERVER_CA_DIR | -| GithubProxy | NGINX_UI_SERVER_GITHUB_PROXY | -| NodeSecret | NGINX_UI_SERVER_NODE_SECRET | -| Demo | NGINX_UI_SERVER_DEMO | -| PageSize | NGINX_UI_SERVER_PAGE_SIZE | -| HttpHost | NGINX_UI_SERVER_HTTP_HOST | -| CertRenewalInterval | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL | -| RecursiveNameservers | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS | -| SkipInstallation | NGINX_UI_SERVER_SKIP_INSTALLATION | -| Name | NGINX_UI_SERVER_NAME | -| InsecureSkipVerify | NGINX_UI_SERVER_INSECURE_SKIP_VERIFY | +| 配置 | 环境变量 | +|---------|--------------------------| +| Host | NGINX_UI_SERVER_HOST | +| Port | NGINX_UI_SERVER_PORT | +| RunMode | NGINX_UI_SERVER_RUN_MODE | -## Nginx +## Database -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------------| -| AccessLogPath | NGINX_UI_NGINX_ACCESS_LOG_PATH | -| ErrorLogPath | NGINX_UI_NGINX_ERROR_LOG_PATH | -| ConfigDir | NGINX_UI_NGINX_CONFIG_DIR | -| PIDPath | NGINX_UI_NGINX_PID_PATH | -| TestConfigCmd | NGINX_UI_NGINX_TEST_CONFIG_CMD | -| ReloadCmd | NGINX_UI_NGINX_RELOAD_CMD | -| RestartCmd | NGINX_UI_NGINX_RESTART_CMD | -| LogDirWhiteList | NGINX_UI_NGINX_LOG_DIR_WHITE_LIST | +| 配置 | 环境变量 | +|------|------------------| +| Name | NGINX_UI_DB_NAME | -## OpenAI +## Auth -| Configuration Setting | Environment Variable | -|-----------------------|--------------------------| -| Model | NGINX_UI_OPENAI_MODEL | -| BaseUrl | NGINX_UI_OPENAI_BASE_URL | -| Proxy | NGINX_UI_OPENAI_PROXY | -| Token | NGINX_UI_OPENAI_TOKEN | +| 配置 | 环境变量 | +|---------------------|-------------------------------------| +| IPWhiteList | NGINX_UI_AUTH_IP_WHITE_LIST | +| BanThresholdMinutes | NGINX_UI_AUTH_BAN_THRESHOLD_MINUTES | +| MaxAttempts | NGINX_UI_AUTH_MAX_ATTEMPTS | ## Casdoor -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------------| -| Endpoint | NGINX_UI_CASDOOR_ENDPOINT | -| ClientId | NGINX_UI_CASDOOR_CLIENT_ID | -| ClientSecret | NGINX_UI_CASDOOR_CLIENT_SECRET | -| CertificatePath | NGINX_UI_CASDOOR_CERTIFICATE_PATH | -| Organization | NGINX_UI_CASDOOR_ORGANIZATION | -| Application | NGINX_UI_CASDOOR_APPLICATION | -| RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI | +| 配置 | 环境变量 | +|-----------------|-----------------------------------| +| Endpoint | NGINX_UI_CASDOOR_ENDPOINT | +| ClientId | NGINX_UI_CASDOOR_CLIENT_ID | +| ClientSecret | NGINX_UI_CASDOOR_CLIENT_SECRET | +| CertificatePath | NGINX_UI_CASDOOR_CERTIFICATE_PATH | +| Organization | NGINX_UI_CASDOOR_ORGANIZATION | +| Application | NGINX_UI_CASDOOR_APPLICATION | +| RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI | + +## Cert + +| 配置 | 环境变量 | +|----------------------|-------------------------------------| +| Email | NGINX_UI_CERT_EMAIL | +| CADir | NGINX_UI_CERT_CA_DIR | +| RenewalInterval | NGINX_UI_CERT_RENEWAL_INTERVAL | +| RecursiveNameservers | NGINX_UI_CERT_RECURSIVE_NAMESERVERS | +| HTTPChallengePort | NGINX_UI_CERT_HTTP_CHALLENGE_PORT | + +## Cluster + +| 配置 | 环境变量 | +|------|-----------------------| +| Node | NGINX_UI_CLUSTER_NODE | + +## Crypto + +| 配置 | 环境变量 | +|--------|------------------------| +| Secret | NGINX_UI_CRYPTO_SECRET | + +## Http + +| 配置 | 环境变量 | +|--------------------|------------------------------------| +| GithubProxy | NGINX_UI_HTTP_GITHUB_PROXY | +| InsecureSkipVerify | NGINX_UI_HTTP_INSECURE_SKIP_VERIFY | ## Logrotate -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------| -| Enabled | NGINX_UI_LOGROTATE_ENABLED | -| CMD | NGINX_UI_LOGROTATE_CMD | -| Interval | NGINX_UI_LOGROTATE_INTERVAL | +| 配置 | 环境变量 | +|----------|-----------------------------| +| Enabled | NGINX_UI_LOGROTATE_ENABLED | +| CMD | NGINX_UI_LOGROTATE_CMD | +| Interval | NGINX_UI_LOGROTATE_INTERVAL | -## Auth +## Nginx + +| 配置 | 环境变量 | +|-----------------|-----------------------------------| +| AccessLogPath | NGINX_UI_NGINX_ACCESS_LOG_PATH | +| ErrorLogPath | NGINX_UI_NGINX_ERROR_LOG_PATH | +| ConfigDir | NGINX_UI_NGINX_CONFIG_DIR | +| PIDPath | NGINX_UI_NGINX_PID_PATH | +| TestConfigCmd | NGINX_UI_NGINX_TEST_CONFIG_CMD | +| ReloadCmd | NGINX_UI_NGINX_RELOAD_CMD | +| RestartCmd | NGINX_UI_NGINX_RESTART_CMD | +| LogDirWhiteList | NGINX_UI_NGINX_LOG_DIR_WHITE_LIST | + +## Node + +| 配置 | 环境变量 | +|------------------|---------------------------------| +| Name | NGINX_UI_NODE_NAME | +| Secret | NGINX_UI_NODE_SECRET | +| SkipInstallation | NGINX_UI_NODE_SKIP_INSTALLATION | + +## OpenAI + +| 配置 | 环境变量 | +|---------|--------------------------| +| Model | NGINX_UI_OPENAI_MODEL | +| BaseUrl | NGINX_UI_OPENAI_BASE_URL | +| Proxy | NGINX_UI_OPENAI_PROXY | +| Token | NGINX_UI_OPENAI_TOKEN | + +## Terminal -| Configuration Setting | Environment Variable | -|-----------------------|---------------------------| -| IPWhiteList | NGINX_UI_AUTH_IPWhiteList | +| 配置 | 环境变量 | +|----------|-----------------------------| +| StartCmd | NGINX_UI_TERMINAL_START_CMD | ## Webauthn -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------------| -| RPDisplayName | NGINX_UI_WEBAUTHN_RP_DISPLAY_NAME | -| RPID | NGINX_UI_WEBAUTHN_RPID | -| RPOrigins | NGINX_UI_WEBAUTHN_RP_ORIGINS | +| 配置 | 环境变量 | +|---------------|-----------------------------------| +| RPDisplayName | NGINX_UI_WEBAUTHN_RP_DISPLAY_NAME | +| RPID | NGINX_UI_WEBAUTHN_RPID | +| RPOrigins | NGINX_UI_WEBAUTHN_RP_ORIGINS | ## 预定义用户 diff --git a/docs/zh_CN/guide/nginx-ui-template.md b/docs/zh_CN/guide/nginx-ui-template.md index 3e5c5fae..20283d1f 100644 --- a/docs/zh_CN/guide/nginx-ui-template.md +++ b/docs/zh_CN/guide/nginx-ui-template.md @@ -4,7 +4,7 @@ Nginx UI Template 提供了一种开箱即用的配置模板机制。在 NgxConf 在本篇指南中,我们将绍这种配置模板的文件格式和语法规则。 配置模板文件存储在 `template/block` 目录中,我们欢迎并期待您通过提交 [PR](https://github.com/0xJacky/nginx-ui/pulls) 的形式分享您编写的配置模板。 -::: tip +::: tip 提示 请注意,每次修改或添加新的配置文件后,需要重新编译后端以生效。 ::: diff --git a/docs/zh_TW/guide/config-app.md b/docs/zh_TW/guide/config-app.md new file mode 100644 index 00000000..3d28e1b9 --- /dev/null +++ b/docs/zh_TW/guide/config-app.md @@ -0,0 +1,20 @@ +# App + +## PageSize + +- 類型: `int` +- 預設值: 10 +- 版本: `>=v2.0.0-beta.37` + +此選項用於設置 Nginx UI 中列表分頁的頁面大小。調整頁面大小可以更有效地管理大量數據,但過大的數字會增加伺服器的負載。 + +## JwtSecret + +- 類型: `string` +- 版本: `>=v2.0.0-beta.37` + +此選項用於配置 Nginx UI 伺服器生成 JWT 的密鑰。 + +JWT 是一種驗證用戶身份的標準。用戶登錄後可以生成一個令牌,然後在後續請求中使用該令牌驗證用戶身份。 + +如果您使用一鍵安裝腳本部署 Nginx UI,腳本將生成一個 UUID 值並將其設置為此選項的值。 diff --git a/docs/zh_TW/guide/config-cert.md b/docs/zh_TW/guide/config-cert.md new file mode 100644 index 00000000..4e5ff7da --- /dev/null +++ b/docs/zh_TW/guide/config-cert.md @@ -0,0 +1,35 @@ +## CADir +- 類型: `string` +- 版本:`>= v2.0.0-beta.37` + +在申請 Let's Encrypt 證書時,我們使用 Let's Encrypt 的默認 CA 地址。 +如果您需要調試或從其他提供商獲取證書,您可以將 CADir 設置為他們的地址。 + +::: tip 提示 +請注意,CADir 提供的地址需要符合 `RFC 8555` 標準。 +::: + +## RecursiveNameservers + +- 版本:`>= v2.0.0-beta.37` +- 類型: `[]string` +- 示例: `8.8.8.8:53,1.1.1.1:53` + +此選項用於設置 Nginx UI 在申請證書的 DNS 挑戰步驟所使用的遞歸域名伺服器。在不配置此項目的情況下,Nginx UI 使用操作系統的域名伺服器設置。 + +## CertRenewalInterval + +- 版本:`>= v2.0.0-beta.37` +- 類型: `int` +- 默認值: `7` + +此選項用於設置 Let's Encrypt 證書的自動續簽間隔。默認情況下,Nginx UI 每隔 7 天會自動續簽證書。 + +## HTTPChallengePort + +- 版本:`>= v2.0.0-beta.37` +- 類型: `int` +- 默認值: `9180` + +在獲取 Let's Encrypt 證書時,此選項用於在 HTTP01 挑戰模式中設置後端監聽端口。 +HTTP01 挑戰是 Let's Encrypt 用於驗證您控制請求證書的域的域驗證方法。 diff --git a/docs/zh_TW/guide/config-database.md b/docs/zh_TW/guide/config-database.md new file mode 100644 index 00000000..3d696cc2 --- /dev/null +++ b/docs/zh_TW/guide/config-database.md @@ -0,0 +1,8 @@ +# Database + +## Name +- 類型: `string` +- 預設值: `database` +- 版本: `>=v2.0.0-beta.37` + +此選項用於設置 Nginx UI 用於存儲其數據的 sqlite 數據庫的名稱。 diff --git a/docs/zh_TW/guide/config-http.md b/docs/zh_TW/guide/config-http.md new file mode 100644 index 00000000..28170ed2 --- /dev/null +++ b/docs/zh_TW/guide/config-http.md @@ -0,0 +1,20 @@ +# Http + +## GithubProxy +- 版本:`>= v2.0.0-beta.37` +- 類型:`string` +- 建議:`https://mirror.ghproxy.com/` + +對於可能在從 Github 下載資源時遇到困難的用戶(如在中國大陸),此選項允許他們為 github.com 設置代理,以提高可訪問性。 + +## InsecureSkipVerify + +- 版本:`>= v2.0.0-beta.37` +- 類型:`bool` + +此選項用於配置 Nginx UI 伺服器在與其他伺服器建立 TLS 連接時是否跳過證書驗證。 + +- 版本:`>= v2.0.0-beta.37` +- 类型: `bool` + +此选项用于配置 Nginx UI 服务器在与其他服务器建立 TLS 连接时是否跳过证书验证。 diff --git a/docs/zh_TW/guide/config-node.md b/docs/zh_TW/guide/config-node.md new file mode 100644 index 00000000..afbc5726 --- /dev/null +++ b/docs/zh_TW/guide/config-node.md @@ -0,0 +1,16 @@ +# Node + +## Name + +- 版本:`>= v2.0.0-beta.37` +- 類型:`string` + +使用此選項自定義本地伺服器的名稱,以在環境指示器中顯示。 + +## Secret + +- 類型: `string` +- 版本: `>= v2.0.0-beta.37` + +此密鑰用於驗證 Nginx UI 伺服器之間的通信。 +此外,您可以使用此密鑰在不使用密碼的情況下訪問 Nginx UI API。 diff --git a/docs/zh_TW/guide/config-server.md b/docs/zh_TW/guide/config-server.md index bf85b867..2e09d795 100644 --- a/docs/zh_TW/guide/config-server.md +++ b/docs/zh_TW/guide/config-server.md @@ -1,89 +1,145 @@ -# 服務端 +# Server -Nginx UI 配置的服務端部分涉及控制 Nginx UI 服務器的各種設置。在頁面中,我們將討論可用的選項、它們的預設值以及它們的目的。 +Nginx UI 配置的服務端部分涉及控制 Nginx UI 伺服器的各種設定。在頁面中,我們將討論可用的選項、它們的預設值以及它們的目的。 -## HttpHost +## Host - 類型: `string` -- 預設值:`0.0.0.0` - -Nginx UI 服務器監聽的主機名。此選項用於配置 Nginx UI 服務器監聽傳入 HTTP 請求的主機名。 更改預設主機名可能有助於提升安全性。 +- 版本: `>= v2.0.0-beta.37` +- 預設值: `0.0.0.0` -## HttpPort +Nginx UI 伺服器監聽的主機名稱。此選項用於配置 Nginx UI 伺服器監聽傳入 HTTP 請求的主機名稱。更改預設主機名稱可能有助於提升安全性。 -- 類型:`int` -- 預設值:`9000` +## Port +- 類型: `uint` +- 版本: `>= v2.0.0-beta.37` +- 預設值: `9000` -Nginx UI 服務器監聽端口。此選項用於配置 Nginx UI 服務器監聽傳入 HTTP 請求的端口。更改預設端口對於避免端口衝突或增強安全性可能很有用。 +此選項用於配置 Nginx UI 伺服器監聽傳入 HTTP 請求的端口。更改預設端口對於避免端口衝突或增強安全性可能很有用。 ## RunMode -- 類型:`string` -- 支援的值:`release`,`debug` -- 預設值:`debug` +- 類型: `string` +- 支援的值: `release`,`debug` +- 預設值: `debug` + +此選項用於配置 Nginx UI 伺服器的運行模式,主要影響日誌輸出的級別。 + +Nginx UI 的日誌分為 6 個級別,分別為 `Debug`、`Info`、`Warn`、`Error`、`Panic` 和 `Fatal`,這些日誌級別按照嚴重程度遞增。 + +當使用 `debug` 模式時,Nginx UI 將在控制台打印 SQL 及其執行的時間和調用者,`Debug` 級別或更高級別的日誌也會被打印。 + +當使用 `release` 模式時,Nginx UI 將不會在控制台打印 SQL 的執行時間和調用者,只有 `Info` 級別或更高級別的日誌才會被打印。 + +## HttpHost +- 類型: `string` +- 預設值: `0.0.0.0` -此選項用於配置 Nginx UI 服務器的運行模式,主要影響日誌打印的級別。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Host` 取代。 +::: -Nginx UI 的日誌分為 6 個級別,分別為 `Debug`、`Info`、`Warn`、`Error`、`Panic` 和 `Fatal`,這些日誌級別按照嚴重程度遞增, +Nginx UI 伺服器監聽的主機名稱。此選項用於配置 Nginx UI 伺服器監聽傳入 HTTP 請求的主機名稱。更改預設主機名稱可能有助於提升安全性。 -當使用 `debug` 模式時,Nginx UI 將在控制台打印 SQL 及其執行的時間和調用者,`Debug` 級別或更高等級的日誌也會被打印。 +## HttpPort +- 類型: `int` +- 預設值: `9000` -當使用 `release` 模式時,Nginx UI 將不會在控制台打印 SQL 的執行時間和調用者, 只有 `Info` 級別或更高等級的日誌才會被打印。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Port` 取代。 +::: + +此選項用於配置 Nginx UI 伺服器監聽傳入 HTTP 請求的端口。更改預設端口對於避免端口衝突或增強安全性可能很有用。 ## JwtSecret -- 類型:`string` +- 類型: `string` -此選項用於配置 Nginx UI 服務器用於生成 JWT 的密鑰。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `App.JwtSecret` 取代。 +::: + +此選項用於配置 Nginx UI 伺服器用於生成 JWT 的密鑰。 + +JWT 是一種用於驗證用戶身份的標準,它可以在用戶登入後生成一個 token,然後在後續的請求中使用該 token 來驗證用戶身份。 + +如果您使用一鍵安裝腳本來部署 Nginx UI,腳本將會生成一個 UUID 值並將它設定為此選項的值。 -JWT 是一種用於驗證用戶身份的標準,它可以在用戶登錄後生成一個 token,然後在後續的請求中使用該 token 來驗證用戶身份。 +## NodeSecret +- 類型: `string` +- 版本: `>= v2.0.0-beta.24, <= 2.0.0-beta.36` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Node.Secret` 取代。 +::: -如果您使用一鍵安裝腳本來部署 Nginx UI,腳本將會生成一個 UUID 值並將它設置為此選項的值。 +此密鑰用於驗證 Nginx UI 伺服器之間的通信。 +此外,您可以使用此密鑰在不使用密碼的情況下訪問 Nginx UI API。 ## HTTPChallengePort -- 類型:`int` -- 預設值:`9180` +- 類型: `int` +- 預設值: `9180` -在獲取 Let's Encrypt 證書時,此選項用於在 HTTP01 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Cert.HTTPChallengePort` 取代。 +::: -挑戰模式中設置後端監聽端口。HTTP01 挑戰是 Let's Encrypt 用於驗證您控制請求證書的域的域驗證方法。 +在獲取 Let's Encrypt 證書時,此選項用於在 HTTP01 挑戰模式中設定後端監聽端口。HTTP01 挑戰是 Let's Encrypt 用於驗證您控制請求證書的域的域驗證方法。 ## Email -- 類型:`string` +- 類型: `string` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Cert.Email` 取代。 +::: -在獲取 Let's Encrypt 證書時,此選項用於設置您的電子郵件地址。Let's Encrypt 會將您的電子郵件地址用於通知您證書的到期時間。 +在獲取 Let's Encrypt 證書時,此選項用於設定您的電子郵件地址。Let's Encrypt 會將您的電子郵件地址用於通知您證書的到期時間。 ## Database -- 類型:`string` -- 預設值:`database` +- 類型: `string` +- 預設值: `database` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Database.Name` 取代。 +::: -此選項用於設置 Nginx UI 用於存儲其數據的 sqlite 數據庫的名稱。 +此選項用於設定 Nginx UI 用於存儲其數據的 sqlite 數據庫的名稱。 ## StartCmd -- 類型:`string` -- 預設值:`login` +- 類型: `string` +- 預設值: `login` -此選項用於設置 Web 終端的啟動命令。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Terminal.StartCmd` 取代。 +::: + +此選項用於設定 Web 終端的啟動命令。 ::: warning 警告 -出於安全原因,我們將啟動命令設置為 `login`,因此您必須通過 Linux 的預設身份驗證方法登錄。如果您不想每次訪問 Web -終端時都輸入用戶名和密碼進行驗證,請將其設置為 `bash` 或 `zsh`(如果已安裝)。 +出於安全原因,我們將啟動命令設置為 `login`,因此您必須通過 Linux 的預設身份驗證方法登入。如果您不想每次訪問 Web 終端時都輸入用戶名和密碼進行驗證,請將其設定為 `bash` 或 `zsh`(如果已安裝)。 ::: ## PageSize -- 類型:`int` -- 預設值:`10` +- 類型: `int` +- 預設值: `10` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `App.PageSize` 取代。 +::: -此選項用於設置 Nginx UI 中列表分頁的頁面大小。調整頁面大小有助於更有效地管理大量數據,但是過大的數量可能會增加服務器的壓力。 +此選項用於設定 Nginx UI 中列表分頁的頁面大小。調整頁面大小有助於更有效地管理大量數據,但是過大的數量可能會增加伺服器的壓力。 ## CADir -- 類型:`string` +- 類型: `string` -在申請 Let's Encrypt 證書時,我們使用 Let's Encrypt 的預設 CA 地址。如果您需要調試或從其他提供商獲取證書,您可以將 CADir -設置為他們的地址。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Cert.CADir` 取代。 +::: + +在申請 Let's Encrypt 證書時,我們使用 Let's Encrypt 的預設 CA 地址。如果您需要調試或從其他提供商獲取證書,您可以將 CADir 設定為他們的地址。 ::: tip 提示 請注意,CADir 提供的地址需要符合 `RFC 8555` 標準。 @@ -91,52 +147,76 @@ JWT 是一種用於驗證用戶身份的標準,它可以在用戶登錄後生 ## GithubProxy -- 類型:`string` -- 建議:`https://mirror.ghproxy.com/` +- 類型: `string` +- 建議: `https://mirror.ghproxy.com/` -對於可能在從 Github 下載資源時遇到困難的用戶(如在中國大陸),此選項允許他們為 github.com 設置代理,以提高可訪問性。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Http.GithubProxy` 取代。 +::: + +對於可能在從 Github 下載資源時遇到困難的用戶(如在中國大陸),此選項允許他們為 github.com 設定代理,以提高可訪問性。 ## CertRenewalInterval -- 版本:`>= v2.0.0-beta.22` -- 類型:`int` +- 版本: `>= v2.0.0-beta.22, <= 2.0.0-beta.36` +- 類型: `int` - 預設值: `7` +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Cert.CertRenewalInterval` 取代。 +::: + 此選項用於設定 Let's Encrypt 證書的自動續簽間隔。預設情況下,Nginx UI 每隔 7 天會自動續簽證書。 ## RecursiveNameservers -- 版本:`>= v2.0.0-beta.22` +- 版本: `>= v2.0.0-beta.22, <= 2.0.0-beta.36` - 類型: `[]string` -- 範例: `8.8.8.8:53,1.1.1.1:53` +- 示例: `8.8.8.8:53,1.1.1.1:53` -此選項用於設定 Nginx UI 在申請證書的 DNS 挑戰步驟所使用的遞迴域名伺服器。在不配置此項目的情況下,Nginx UI 使用作業系統的域名伺服器設定。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 + +`Cert.RecursiveNameservers` 取代。 +::: + +此選項用於設定 Nginx UI 在申請證書的 DNS 挑戰步驟中所使用的遞歸域名伺服器。在不配置此項目的情況下,Nginx UI 使用操作系統的域名伺服器設置。 ## SkipInstallation -- 版本:`>= v2.0.0-beta.23` -- 類型:`bool` -- 預設值:`false` +- 版本: `>= v2.0.0-beta.23, <= 2.0.0-beta.36` +- 類型: `bool` +- 預設值: `false` -透過將此選項設定為 `true`,您可以跳過 Nginx UI 伺服器的安裝。 -當您希望使用相同的配置文件或環境變數將 Nginx UI 部署到多個伺服器時,這非常有用。 +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Node.SkipInstallation` 取代。 +::: -預設情況下,如果您啟用了跳過安裝模式,而沒有在伺服器部分設定 `JWTSecret` 和 `NodeSecret` 選項, -Nginx UI 將為這兩個選項生成一個隨機的 UUID 值。 +通過將此選項設置為 `true`,您可以跳過 Nginx UI 伺服器的安裝。 +當您希望使用相同的配置文件或環境變量將 Nginx UI 部署到多個伺服器時,這非常有用。 -此外,如果您也沒有在伺服器部分設定 `Email` 選項, -Nginx UI 將不會創建系統初始的 acme 使用者,這意味著您無法在此伺服器上申請 SSL 證書。 +預設情況下,如果您啟用了跳過安裝模式,而沒有在伺服器部分設置 `JWTSecret` 和 `NodeSecret` 選項,Nginx UI 將為這兩個選項生成一個隨機的 UUID 值。 + +此外,如果您也沒有在伺服器部分設置 `Email` 選項,Nginx UI 將不會創建系統初始的 acme 用戶,這意味著您無法在此伺服器上申請 SSL 證書。 ## Name -- 版本:`>= v2.0.0-beta.23` -- 類型:`string` +- 版本: `>= v2.0.0-beta.23, <= 2.0.0-beta.36` +- 類型: `string` + +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Http.InsecureSkipVerify` 取代。 +::: 使用此選項自定義本地伺服器的名稱,以在環境指示器中顯示。 ## InsecureSkipVerify -- 版本:`>= v2.0.0-beta.30` +- 版本: `>= v2.0.0-beta.30, <= 2.0.0-beta.36` - 類型: `bool` +::: warning 警告 +已在 `v2.0.0-beta.37` 中廢棄,請使用 `Http.InsecureSkipVerify` 取代。 +::: + 此選項用於配置 Nginx UI 伺服器在與其他伺服器建立 TLS 連接時是否跳過證書驗證。 diff --git a/docs/zh_TW/guide/config-terminal.md b/docs/zh_TW/guide/config-terminal.md new file mode 100644 index 00000000..6b673591 --- /dev/null +++ b/docs/zh_TW/guide/config-terminal.md @@ -0,0 +1,14 @@ +# Terminal + +## StartCmd + +- 類型: `string` +- 預設值: `login` +- 版本: `>= v2.0.0-beta.37` + +此選項用於設置 Web 終端的啟動命令。 + +::: warning 警告 +出於安全原因,我們將啟動命令設置為 `login`,因此您必須通過 Linux 的預設身份驗證方法登錄。 +如果您不想每次訪問 Web 終端時都輸入用戶名和密碼進行驗證,請將其設置為 `bash` 或 `zsh`(如果已安裝)。 +::: diff --git a/docs/zh_TW/guide/env.md b/docs/zh_TW/guide/env.md index 19bd285d..14585a11 100644 --- a/docs/zh_TW/guide/env.md +++ b/docs/zh_TW/guide/env.md @@ -1,88 +1,132 @@ # 環境變量 -適用於 v2.0.0-beta.23 及以上版本 +適用於 v2.0.0-beta.37 及以上版本。 + +## App + +| 配置 | 環境變量 | +|-----------|-------------------------| +| PageSize | NGINX_UI_APP_PAGE_SIZE | +| JwtSecret | NGINX_UI_APP_JWT_SECRET | ## Server -| Configuration Setting | Environment Variable | -|-----------------------|---------------------------------------| -| HttpPort | NGINX_UI_SERVER_HTTP_PORT | -| RunMode | NGINX_UI_SERVER_RUN_MODE | -| JwtSecret | NGINX_UI_SERVER_JWT_SECRET | -| HTTPChallengePort | NGINX_UI_SERVER_HTTP_CHALLENGE_PORT | -| StartCmd | NGINX_UI_SERVER_START_CMD | -| Database | NGINX_UI_SERVER_DATABASE | -| CADir | NGINX_UI_SERVER_CA_DIR | -| GithubProxy | NGINX_UI_SERVER_GITHUB_PROXY | -| NodeSecret | NGINX_UI_SERVER_NODE_SECRET | -| Demo | NGINX_UI_SERVER_DEMO | -| PageSize | NGINX_UI_SERVER_PAGE_SIZE | -| HttpHost | NGINX_UI_SERVER_HTTP_HOST | -| CertRenewalInterval | NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL | -| RecursiveNameservers | NGINX_UI_SERVER_RECURSIVE_NAMESERVERS | -| SkipInstallation | NGINX_UI_SERVER_SKIP_INSTALLATION | -| Name | NGINX_UI_SERVER_NAME | -| InsecureSkipVerify | NGINX_UI_SERVER_INSECURE_SKIP_VERIFY | +| 配置 | 環境變量 | +|---------|--------------------------| +| Host | NGINX_UI_SERVER_HOST | +| Port | NGINX_UI_SERVER_PORT | +| RunMode | NGINX_UI_SERVER_RUN_MODE | -## Nginx +## Database -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------------| -| AccessLogPath | NGINX_UI_NGINX_ACCESS_LOG_PATH | -| ErrorLogPath | NGINX_UI_NGINX_ERROR_LOG_PATH | -| ConfigDir | NGINX_UI_NGINX_CONFIG_DIR | -| PIDPath | NGINX_UI_NGINX_PID_PATH | -| TestConfigCmd | NGINX_UI_NGINX_TEST_CONFIG_CMD | -| ReloadCmd | NGINX_UI_NGINX_RELOAD_CMD | -| RestartCmd | NGINX_UI_NGINX_RESTART_CMD | -| LogDirWhiteList | NGINX_UI_NGINX_LOG_DIR_WHITE_LIST | +| 配置 | 環境變量 | +|------|------------------| +| Name | NGINX_UI_DB_NAME | -## OpenAI +## Auth -| Configuration Setting | Environment Variable | -|-----------------------|--------------------------| -| Model | NGINX_UI_OPENAI_MODEL | -| BaseUrl | NGINX_UI_OPENAI_BASE_URL | -| Proxy | NGINX_UI_OPENAI_PROXY | -| Token | NGINX_UI_OPENAI_TOKEN | +| 配置 | 環境變量 | +|---------------------|-------------------------------------| +| IPWhiteList | NGINX_UI_AUTH_IP_WHITE_LIST | +| BanThresholdMinutes | NGINX_UI_AUTH_BAN_THRESHOLD_MINUTES | +| MaxAttempts | NGINX_UI_AUTH_MAX_ATTEMPTS | ## Casdoor -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------------| -| Endpoint | NGINX_UI_CASDOOR_ENDPOINT | -| ClientId | NGINX_UI_CASDOOR_CLIENT_ID | -| ClientSecret | NGINX_UI_CASDOOR_CLIENT_SECRET | -| CertificatePath | NGINX_UI_CASDOOR_CERTIFICATE_PATH | -| Organization | NGINX_UI_CASDOOR_ORGANIZATION | -| Application | NGINX_UI_CASDOOR_APPLICATION | -| RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI | +| 配置 | 環境變量 | +|-----------------|-----------------------------------| +| Endpoint | NGINX_UI_CASDOOR_ENDPOINT | +| ClientId | NGINX_UI_CASDOOR_CLIENT_ID | +| ClientSecret | NGINX_UI_CASDOOR_CLIENT_SECRET | +| CertificatePath | NGINX_UI_CASDOOR_CERTIFICATE_PATH | +| Organization | NGINX_UI_CASDOOR_ORGANIZATION | +| Application | NGINX_UI_CASDOOR_APPLICATION | +| RedirectUri | NGINX_UI_CASDOOR_REDIRECT_URI | + +## Cert + +| 配置 | 環境變量 | +|----------------------|-------------------------------------| +| Email | NGINX_UI_CERT_EMAIL | +| CADir | NGINX_UI_CERT_CA_DIR | +| RenewalInterval | NGINX_UI_CERT_RENEWAL_INTERVAL | +| RecursiveNameservers | NGINX_UI_CERT_RECURSIVE_NAMESERVERS | +| HTTPChallengePort | NGINX_UI_CERT_HTTP_CHALLENGE_PORT | + +## Cluster + +| 配置 | 環境變量 | +|------|-----------------------| +| Node | NGINX_UI_CLUSTER_NODE | + +## Crypto + +| 配置 | 環境變量 | +|--------|------------------------| +| Secret | NGINX_UI_CRYPTO_SECRET | + +## Http + +| 配置 | 環境變量 | +|--------------------|------------------------------------| +| GithubProxy | NGINX_UI_HTTP_GITHUB_PROXY | +| InsecureSkipVerify | NGINX_UI_HTTP_INSECURE_SKIP_VERIFY | ## Logrotate -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------| -| Enabled | NGINX_UI_LOGROTATE_ENABLED | -| CMD | NGINX_UI_LOGROTATE_CMD | -| Interval | NGINX_UI_LOGROTATE_INTERVAL | +| 配置 | 環境變量 | +|----------|-----------------------------| +| Enabled | NGINX_UI_LOGROTATE_ENABLED | +| CMD | NGINX_UI_LOGROTATE_CMD | +| Interval | NGINX_UI_LOGROTATE_INTERVAL | -## Auth +## Nginx + +| 配置 | 環境變量 | +|-----------------|-----------------------------------| +| AccessLogPath | NGINX_UI_NGINX_ACCESS_LOG_PATH | +| ErrorLogPath | NGINX_UI_NGINX_ERROR_LOG_PATH | +| ConfigDir | NGINX_UI_NGINX_CONFIG_DIR | +| PIDPath | NGINX_UI_NGINX_PID_PATH | +| TestConfigCmd | NGINX_UI_NGINX_TEST_CONFIG_CMD | +| ReloadCmd | NGINX_UI_NGINX_RELOAD_CMD | +| RestartCmd | NGINX_UI_NGINX_RESTART_CMD | +| LogDirWhiteList | NGINX_UI_NGINX_LOG_DIR_WHITE_LIST | + +## Node + +| 配置 | 環境變量 | +|------------------|---------------------------------| +| Name | NGINX_UI_NODE_NAME | +| Secret | NGINX_UI_NODE_SECRET | +| SkipInstallation | NGINX_UI_NODE_SKIP_INSTALLATION | + +## OpenAI + +| 配置 | 環境變量 | +|---------|--------------------------| +| Model | NGINX_UI_OPENAI_MODEL | +| BaseUrl | NGINX_UI_OPENAI_BASE_URL | +| Proxy | NGINX_UI_OPENAI_PROXY | +| Token | NGINX_UI_OPENAI_TOKEN | + +## Terminal -| Configuration Setting | Environment Variable | -|-----------------------|---------------------------| -| IPWhiteList | NGINX_UI_AUTH_IPWhiteList | +| 配置 | 環境變量 | +|----------|-----------------------------| +| StartCmd | NGINX_UI_TERMINAL_START_CMD | ## Webauthn -| Configuration Setting | Environment Variable | -|-----------------------|-----------------------------------| -| RPDisplayName | NGINX_UI_WEBAUTHN_RP_DISPLAY_NAME | -| RPID | NGINX_UI_WEBAUTHN_RPID | -| RPOrigins | NGINX_UI_WEBAUTHN_RP_ORIGINS | +| 配置 | 環境變量 | +|---------------|-----------------------------------| +| RPDisplayName | NGINX_UI_WEBAUTHN_RP_DISPLAY_NAME | +| RPID | NGINX_UI_WEBAUTHN_RPID | +| RPOrigins | NGINX_UI_WEBAUTHN_RP_ORIGINS | -## 預定義使用者 +## 預定義用戶 -在跳過安裝模式下,您可以設置以下環境變量以創建預定義使用者: +在跳過安裝模式下,您可以設定以下環境變量以創建預定義用戶: - NGINX_UI_PREDEFINED_USER_NAME - NGINX_UI_PREDEFINED_USER_PASSWORD diff --git a/go.mod b/go.mod index 4ac64e22..f232b436 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/dgraph-io/ristretto v1.0.0 github.com/dustin/go-humanize v1.0.1 github.com/elliotchance/orderedmap/v2 v2.4.0 - github.com/fatih/color v1.17.0 + github.com/fatih/color v1.18.0 github.com/gin-contrib/static v1.1.2 github.com/gin-gonic/gin v1.10.0 github.com/go-acme/lego/v4 v4.19.2 @@ -29,7 +29,7 @@ require ( github.com/pquerna/otp v1.4.0 github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308 github.com/samber/lo v1.47.0 - github.com/sashabaranov/go-openai v1.32.2 + github.com/sashabaranov/go-openai v1.32.3 github.com/shirou/gopsutil/v3 v3.24.5 github.com/spf13/cast v1.7.0 github.com/stretchr/testify v1.9.0 @@ -72,7 +72,7 @@ require ( github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect github.com/StackExchange/wmi v1.2.1 // indirect github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect - github.com/aliyun/alibaba-cloud-sdk-go v1.63.32 // indirect + github.com/aliyun/alibaba-cloud-sdk-go v1.63.34 // indirect github.com/aws/aws-sdk-go-v2 v1.32.2 // indirect github.com/aws/aws-sdk-go-v2/config v1.28.0 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.41 // indirect @@ -221,8 +221,8 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.19.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1026 // indirect - github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1026 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1028 // indirect + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1028 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect github.com/tklauser/go-sysconf v0.3.14 // indirect github.com/tklauser/numcpus v0.9.0 // indirect @@ -233,8 +233,8 @@ require ( github.com/vinyldns/go-vinyldns v0.9.16 // indirect github.com/vultr/govultr/v3 v3.10.0 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/yandex-cloud/go-genproto v0.0.0-20241018072940-69706eaae3be // indirect - github.com/yandex-cloud/go-sdk v0.0.0-20241018073342-0142f4806660 // indirect + github.com/yandex-cloud/go-genproto v0.0.0-20241021132621-28bb61d00c2f // indirect + github.com/yandex-cloud/go-sdk v0.0.0-20241021153520-213d4c625eca // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver v1.17.1 // indirect go.opencensus.io v0.24.0 // indirect @@ -256,9 +256,9 @@ require ( golang.org/x/time v0.7.0 // indirect golang.org/x/tools v0.26.0 // indirect google.golang.org/api v0.201.0 // indirect - google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect + google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect google.golang.org/grpc v1.67.1 // indirect google.golang.org/protobuf v1.35.1 // indirect gopkg.in/fsnotify.v1 v1.4.7 // indirect diff --git a/go.sum b/go.sum index 9a17ffe0..9c642ea8 100644 --- a/go.sum +++ b/go.sum @@ -39,6 +39,7 @@ cloud.google.com/go v0.104.0/go.mod h1:OO6xxXdJyvuJPcEPBLN9BJPD+jep5G1+2U5B5gkRY cloud.google.com/go v0.105.0/go.mod h1:PrLgOJNe5nfE9UMxKxgXj4mD3voiP+YQ6gdt6KMFOKM= cloud.google.com/go v0.107.0/go.mod h1:wpc2eNrD7hXUTy8EKS10jkxpZBjASrORK7goS+3YX2I= cloud.google.com/go v0.110.0/go.mod h1:SJnCLqQ0FCFGSZMUNUf84MV3Aia54kn7pi8st7tMzaY= +cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= cloud.google.com/go/accessapproval v1.4.0/go.mod h1:zybIuC3KpDOvotz59lFe5qxRZx6C75OtwbisN56xYB4= cloud.google.com/go/accessapproval v1.5.0/go.mod h1:HFy3tuiGvMdcd/u+Cu5b9NkO1pEICJ46IR82PoUdplw= cloud.google.com/go/accessapproval v1.6.0/go.mod h1:R0EiYnwV5fsRFiKZkPHr6mwyk2wxUJ30nL4j2pcFY2E= @@ -178,6 +179,7 @@ cloud.google.com/go/compute v1.14.0/go.mod h1:YfLtxrj9sU4Yxv+sXzZkyPjEyPBZfXHUvj cloud.google.com/go/compute v1.15.1/go.mod h1:bjjoF/NtFUrkD/urWfdHaKuOPDR5nWIs63rR+SXhcpA= cloud.google.com/go/compute v1.18.0/go.mod h1:1X7yHxec2Ga+Ss6jPyjxRxpu2uu7PLgsOVXvgU0yacs= cloud.google.com/go/compute v1.19.0/go.mod h1:rikpw2y+UMidAe9tISo04EHNOIf42RLYF/q8Bs93scU= +cloud.google.com/go/compute v1.28.1 h1:XwPcZjgMCnU2tkwY10VleUjSAfpTj9RDn+kGrbYsi8o= cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU= cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM= @@ -685,6 +687,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/aliyun/alibaba-cloud-sdk-go v1.63.32 h1:aBtZr6N7HXVpJCMybTSBuinHauehf/R0LNMB03TkrE0= github.com/aliyun/alibaba-cloud-sdk-go v1.63.32/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.34 h1:eZM2MHY/p4TFO1pGf9O5HiuYE59hwrrkf3HvCtkL5Ok= +github.com/aliyun/alibaba-cloud-sdk-go v1.63.34/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0= @@ -760,6 +764,7 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -852,6 +857,8 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -1554,6 +1561,8 @@ github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/sashabaranov/go-openai v1.32.2 h1:8z9PfYaLPbRzmJIYpwcWu6z3XU8F+RwVMF1QRSeSF2M= github.com/sashabaranov/go-openai v1.32.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= +github.com/sashabaranov/go-openai v1.32.3 h1:6xZ393PbZFoJrgwveBXVZggmyH7zdp4joUdnCy7FFD8= +github.com/sashabaranov/go-openai v1.32.3/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30 h1:yoKAVkEVwAqbGbR8n87rHQ1dulL25rKloGadb3vm770= github.com/scaleway/scaleway-sdk-go v1.0.0-beta.30/go.mod h1:sH0u6fq6x4R5M7WxkoQFY/o7UaiItec0o1LinLCJNq8= @@ -1653,8 +1662,12 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1026 h1:6iBtl1CunsfWcT6IyCuRdgefJ/Zmsp5MTDujnolyuQs= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1026/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1028 h1:3rMKraYsxf5bQ4KglyzQ91vXZUXpUhn2Cdz9HkL125o= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1028/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1026 h1:W6wPKS41uNKs7RBcJP5iB0HrcglXNSFUmnQaBEorVpg= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1026/go.mod h1:aqLJU0aRU1k7l+TPyYCao+KQHrFEF6lNQqK04FIiLJw= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1028 h1:brTlgS0nWHFzw8aI67OEqEwpXhyeT781FDXV3bIEj/w= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1028/go.mod h1:7dV6qKKfZ+x2iNcq4Drb5Pb1P/gNHg12R4xPy6+bo0M= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= @@ -1700,8 +1713,12 @@ github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yandex-cloud/go-genproto v0.0.0-20241018072940-69706eaae3be h1:jGNL9PedKrHWl1WCRdlBEFo7nDl589LKvkulZRf7ZTA= github.com/yandex-cloud/go-genproto v0.0.0-20241018072940-69706eaae3be/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo= +github.com/yandex-cloud/go-genproto v0.0.0-20241021132621-28bb61d00c2f h1:u7ETK40lM4ygnDzYtGFLk36fWARftvU+I0zwTYrOVwE= +github.com/yandex-cloud/go-genproto v0.0.0-20241021132621-28bb61d00c2f/go.mod h1:0LDD/IZLIUIV4iPH+YcF+jysO3jkSvADFGm4dCAuwQo= github.com/yandex-cloud/go-sdk v0.0.0-20241018073342-0142f4806660 h1:/XDcP3XiGxwW6GGYzjHtQ82ZEEdpCuDQlmmsmx6Zyuc= github.com/yandex-cloud/go-sdk v0.0.0-20241018073342-0142f4806660/go.mod h1:7Ru6CfLQ1pfa5WcWdzdr8UY7xRsvVTykxBh5dzjx+Ic= +github.com/yandex-cloud/go-sdk v0.0.0-20241021153520-213d4c625eca h1:m3Hne9w8jnfiPPDw9KqSLtRa7Et+gzCIub2ky5uUGGM= +github.com/yandex-cloud/go-sdk v0.0.0-20241021153520-213d4c625eca/go.mod h1:id1/mPjMDlqamdsay74AJLVVLGCRTnjMIKuXpNzVN08= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -2457,10 +2474,16 @@ google.golang.org/genproto v0.0.0-20230331144136-dcfb400f0633/go.mod h1:UUQDJDOl google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53 h1:Df6WuGvthPzc+JiQ/G+m+sNX24kc0aTBqoDN/0yyykE= google.golang.org/genproto v0.0.0-20241015192408-796eee8c2d53/go.mod h1:fheguH3Am2dGp1LfXkrvwqC/KlFq8F0nLq3LryOMrrE= +google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38 h1:Q3nlH8iSQSRUwOskjbcSMcF2jiYMNiQYZ0c2KEJLKKU= +google.golang.org/genproto v0.0.0-20241021214115-324edc3d5d38/go.mod h1:xBI+tzfqGGN2JBeSebfKXFSdBpWVQ7sLW40PTupVRm4= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U= google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38 h1:2oV8dfuIkM1Ti7DwXc0BJfnwr9csz4TDXI9EmiI+Rbw= +google.golang.org/genproto/googleapis/api v0.0.0-20241021214115-324edc3d5d38/go.mod h1:vuAjtvlwkDKF6L1GQ0SokiRLCGFfeBUXWr/aFFkHACc= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE= google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= diff --git a/install.sh b/install.sh index 715a5738..7a9e72a3 100644 --- a/install.sh +++ b/install.sh @@ -290,12 +290,15 @@ install_config() { if [[ ! -f "$DataPath/app.ini" ]]; then cat > "$DataPath/app.ini" << EOF [server] -HOST = 127.0.0.1 +HOST = 0.0.0.0 PORT = 9000 RunMode = release [cert] -HTTPChallengePort = 9180 +HTTPChallengePort = 9180 + +[terminal] +StartCmd = login EOF echo "info: The default configuration file was installed to '$DataPath/app.ini' successfully!" fi diff --git a/internal/kernal/boot.go b/internal/kernal/boot.go index a2256a82..8cb59659 100644 --- a/internal/kernal/boot.go +++ b/internal/kernal/boot.go @@ -80,7 +80,7 @@ func InitDatabase() { } if "" != cSettings.AppSettings.JwtSecret { - db := cosy.InitDB(sqlite.Open(path.Dir(cSettings.ConfPath), cSettings.DataBaseSettings)) + db := cosy.InitDB(sqlite.Open(path.Dir(cSettings.ConfPath), settings.DatabaseSettings)) model.Use(db) query.Init(db) diff --git a/model/model.go b/model/model.go index bf5392e6..6c76186e 100644 --- a/model/model.go +++ b/model/model.go @@ -55,14 +55,6 @@ type DataList struct { Pagination Pagination `json:"pagination,omitempty"` } -func TotalPage(total int64, pageSize int) int64 { - n := total / int64(pageSize) - if total%int64(pageSize) > 0 { - n++ - } - return n -} - type Method interface { // FirstByID Where("id=@id") FirstByID(id int) (*gen.T, error) diff --git a/settings/database.go b/settings/database.go new file mode 100644 index 00000000..7e35f1c8 --- /dev/null +++ b/settings/database.go @@ -0,0 +1,11 @@ +package settings + +type Database struct { + Name string +} + +var DatabaseSettings = &Database{} + +func (d *Database) GetName() string { + return d.Name +} diff --git a/settings/server_v1.go b/settings/server_v1.go index 3f1118b7..7f54d066 100644 --- a/settings/server_v1.go +++ b/settings/server_v1.go @@ -37,7 +37,7 @@ type settingsV2 struct { // Cosy App settings.App Server settings.Server - DataBase settings.DataBase + DataBase Database // Nginx UI Auth Auth Casdoor Casdoor @@ -121,7 +121,7 @@ func Migrate(confPath string) { // Cosy app := &settings.App{} server := &settings.Server{} - database := &settings.DataBase{} + database := &Database{} // Nginx UI auth := &Auth{} casdoor := &Casdoor{} diff --git a/settings/settings.go b/settings/settings.go index 099a9b18..e763ecdc 100644 --- a/settings/settings.go +++ b/settings/settings.go @@ -23,8 +23,8 @@ var envPrefixMap = map[string]interface{}{ // Cosy "APP": settings.AppSettings, "SERVER": settings.ServerSettings, - "DB": settings.DataBaseSettings, // Nginx UI + "DB": DatabaseSettings, "AUTH": AuthSettings, "CASDOOR": CasdoorSettings, "CERT": CertSettings, From f8e17dc7e43d64a1fd5f4bbe60cc80cf43aee7c0 Mon Sep 17 00:00:00 2001 From: Jacky Date: Wed, 23 Oct 2024 00:01:31 +0800 Subject: [PATCH 05/13] chore: deploy docs only when push to dev or main --- .github/workflows/documents.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/documents.yml b/.github/workflows/documents.yml index 6f0e7d27..e0f65f9d 100644 --- a/.github/workflows/documents.yml +++ b/.github/workflows/documents.yml @@ -3,7 +3,8 @@ name: Build Documents on: push: branches: - - '*' + - 'dev' + - 'main' paths: - "docs/**/*.js" - "docs/**/*.ts" From 925e61abf43bb1c51ce89e97431600b3d1b5cfd1 Mon Sep 17 00:00:00 2001 From: Jacky Date: Wed, 23 Oct 2024 11:48:41 +0800 Subject: [PATCH 06/13] fix: update demo database and app.ini; enhance: migration --- .gitignore | 2 + install.sh | 3 ++ resources/demo/app.ini | 80 ++++++++++++++++++++++++++++++++----- resources/demo/demo.db | Bin 65536 -> 131072 bytes settings/database.go | 4 +- settings/server_v1.go | 4 ++ settings/server_v1_test.go | 2 +- settings/settings.go | 3 +- 8 files changed, 84 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 095b6dbf..c4a0697c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ resources/development/nginx app/.env app/.status_hash casdoor.pub +.idea/deployment.xml +.idea/webServers.xml diff --git a/install.sh b/install.sh index 7a9e72a3..20976d0f 100644 --- a/install.sh +++ b/install.sh @@ -289,6 +289,9 @@ install_config() { mkdir -p "$DataPath" if [[ ! -f "$DataPath/app.ini" ]]; then cat > "$DataPath/app.ini" << EOF +[app] +PageSize = 10 + [server] HOST = 0.0.0.0 PORT = 9000 diff --git a/resources/demo/app.ini b/resources/demo/app.ini index 78d30fef..097ac0a0 100644 --- a/resources/demo/app.ini +++ b/resources/demo/app.ini @@ -1,19 +1,77 @@ +[app] +PageSize = 10 +JwtSecret = 6EEB622E-5C73-4082-AF76-7BAC337772F2 + [server] -HttpPort = 9000 +Host = +Port = 9000 RunMode = release -JwtSecret = 6EEB622E-5C73-4082-AF76-7BAC337772F2 -Email = test@jackyu.cn -HTTPChallengePort = 9180 -StartCmd = bash -NodeSecret = 57D079F2-CA8B-412A-B5C0-FDA291C13391 -Demo = true + +[database] +Name = database + +[auth] +IPWhiteList = +BanThresholdMinutes = 10 +MaxAttempts = 10 + +[casdoor] +Endpoint = +ClientId = +ClientSecret = +CertificatePath = +Organization = +Application = +RedirectUri = + +[cert] +Email = test@jackyu.cn +CADir = https://acme-staging-v02.api.letsencrypt.org/directory +RenewalInterval = 0 +RecursiveNameservers = +HTTPChallengePort = 9180 + +[cluster] +Node = + +[crypto] +Secret = 4a82fe17c5aab629007462b303c367d2863b7db28b95c8f869f2f815672d41d8 + +[http] +GithubProxy = +InsecureSkipVerify = false + +[logrotate] +Enabled = false +CMD = logrotate /etc/logrotate.d/nginx +Interval = 0 [nginx] -AccessLogPath = -ErrorLogPath = +AccessLogPath = +ErrorLogPath = +LogDirWhiteList = /var/log/nginx +ConfigDir = +PIDPath = +TestConfigCmd = +ReloadCmd = +RestartCmd = + +[node] +Name = +Secret = 57D079F2-CA8B-412A-B5C0-FDA291C13391 +SkipInstallation = false +Demo = true [openai] -Model = gpt-3.5-turbo BaseUrl = -Proxy = Token = +Proxy = +Model = gpt-3.5-turbo + +[terminal] +StartCmd = bash + +[webauthn] +RPDisplayName = +RPID = +RPOrigins = diff --git a/resources/demo/demo.db b/resources/demo/demo.db index 2f78552ff1af25c238531275bb042bc53b15199b..2ae6cf1c96dbd652e7a61833e778c8166be65607 100644 GIT binary patch delta 5223 zcmeHL-EZ4e6t`O^&bJfxVY)7@yQx~EX0-c|V02{-YZ#>;%StEM1GC-auJcH2*LJoH zSY0^5ut^h7NF$H%0OB9ujTgpvKukRBg%`As2d*7|CIuzPllxa{CISG_#RP4n zg?b1iX)A}xaSUq>J6}PNNfUU@M36z0i;NY?h2v9m z@Uhwa+=AX0n$+J5r`62){Wy7K0M&Y&rDTg0Kv!iTc~QB-E$zTur6&$eY_6&WUSVI5 z93EEDQ%!WsWljOK43?{aF9O+r`-~54i*kr(D%&cu6#mRvIw0^<#=??8)rF@x zv~p1dR)i@=0x^jsEcK2Y0VqDD}yBguBU7OqKigy z(Q;M9L_ty-SHqW4{i8Stzcpx1uHK_RjIZy5C=^zyLf8KUUlCz$7bT!D)M8m!ycXTs zxSm)<^~55gH3d#?qf=RmX%tY(N|TI|Svox~~zTVJiRZK?UB}Uvwh{wcV#Gl0dM)Jp0LQmeU=^x*DSMR-}=vVH7 zEm(IP#f+bBqBUkcM{X7^=hU#Og=gPelFg!J5)tR5kvEH$NufF^T3z#- zMeBc7v`%+ev>-1S&BS3nN(E9#;P z?lKG68)Qo66#bmYOs{i?TU)iFz@Ookyg{-gJCDw*tvzbHaWh7i+znAPLTARzUah{{ zjF4qy{q^|cV|$>yty-`2FTL6dv7m~qa@KAkHb{zWlSd2ZfpkHF>FF@h%#)!}s+WLv z)T=+4R$cWibLOdcLVZRz*UAPq-xydge_X!gIa6HW<{N`hq4*Tu82q=bxxNzGaU+?$ OHW4*@y9UNQ?*AJ)2mj{) delta 546 zcmZo@;Am)InIJ7F$iToL0K_m5HBrY{TaZD|zm^v$#LqUJk=LH*9=|%@Jl+qyJzQ3t zYq=}AMLGU(%wRvu?#niPv!H+rs|V*&#&U6GWkzmM2;Hh*l9-f}nw(lxQXC&&lA2q9 z#AJ02a&-)GRS0o(@^Mv2K$1zA+{YI*c|IqHAp--GhPa_2V^ciXpwzsw%%c3f+|)dn zc@U9CV|{jUb#=xj)yaK~@{{+na!lUJDCVr8l$oNWkeOGKnx0yuqm*2fnpl#W5}#P2 zq)?JtQKF+%T9AS!l9HN}imYa`G?UI`F17})Mh{(faaC2urr_!C)-kS|oXR7zc{#fX z<7PqbbVkOO$-6mHxSEnQ*~P`h8C#V%YjS!pPUhw>;qYc<1BFQZlt0oZ6~j zHBF|IpYcot8Y8@U4{s9VvJH#^n-o|KIGFf;G4R*&{hBNgATwDZfMv5zKp;O$BLgGz z=EnH?0s&q=E(R7}X$JldUTNNbeu2#b7X Date: Wed, 23 Oct 2024 11:48:58 +0800 Subject: [PATCH 07/13] enhance: user token storage --- app/src/components/TwoFA/Authorization.vue | 2 +- app/src/components/TwoFA/use2FAModal.ts | 9 +-- app/src/lib/http/index.ts | 4 +- app/src/pinia/moudule/user.ts | 90 ++++++++++++++-------- app/src/views/other/Login.vue | 9 +-- 5 files changed, 66 insertions(+), 48 deletions(-) diff --git a/app/src/components/TwoFA/Authorization.vue b/app/src/components/TwoFA/Authorization.vue index d572e552..c6b82388 100644 --- a/app/src/components/TwoFA/Authorization.vue +++ b/app/src/components/TwoFA/Authorization.vue @@ -46,7 +46,7 @@ async function passkeyAuthenticate() { passkeyLoading.value = true try { const begin = await twoFA.begin_start_secure_session_by_passkey() - const asseResp = await startAuthentication(begin.options.publicKey) + const asseResp = await startAuthentication({ optionsJSON: begin.options.publicKey }) const r = await twoFA.finish_start_secure_session_by_passkey({ session_id: begin.session_id, diff --git a/app/src/components/TwoFA/use2FAModal.ts b/app/src/components/TwoFA/use2FAModal.ts index c6be576e..07b39d54 100644 --- a/app/src/components/TwoFA/use2FAModal.ts +++ b/app/src/components/TwoFA/use2FAModal.ts @@ -1,6 +1,5 @@ import { createVNode, render } from 'vue' import { Modal, message } from 'ant-design-vue' -import { useCookies } from '@vueuse/integrations/useCookies' import Authorization from '@/components/TwoFA/Authorization.vue' import twoFA from '@/api/2fa' import { useUserStore } from '@/pinia' @@ -32,11 +31,8 @@ const use2FAModal = () => { return } - const cookies = useCookies(['nginx-ui-2fa']) - const ssid = cookies.get('secure_session_id') - if (ssid && secureSessionStatus) { - resolve(ssid) - secureSessionId.value = ssid + if (secureSessionId.value && secureSessionStatus) { + resolve(secureSessionId.value) return } @@ -51,7 +47,6 @@ const use2FAModal = () => { } const setSessionId = (sessionId: string) => { - cookies.set('secure_session_id', sessionId, { maxAge: 60 * 3 }) close() secureSessionId.value = sessionId resolve(sessionId) diff --git a/app/src/lib/http/index.ts b/app/src/lib/http/index.ts index 3543319c..fb3de769 100644 --- a/app/src/lib/http/index.ts +++ b/app/src/lib/http/index.ts @@ -1,6 +1,5 @@ import type { AxiosRequestConfig } from 'axios' import axios from 'axios' -import { useCookies } from '@vueuse/integrations/useCookies' import { storeToRefs } from 'pinia' import NProgress from 'nprogress' import { useSettingsStore, useUserStore } from '@/pinia' @@ -62,10 +61,9 @@ instance.interceptors.response.use( NProgress.done() const otpModal = use2FAModal() - const cookies = useCookies(['nginx-ui-2fa']) switch (error.response.status) { case 401: - cookies.remove('secure_session_id') + secureSessionId.value = '' await otpModal.open() break case 403: diff --git a/app/src/pinia/moudule/user.ts b/app/src/pinia/moudule/user.ts index c7c77acd..50b03807 100644 --- a/app/src/pinia/moudule/user.ts +++ b/app/src/pinia/moudule/user.ts @@ -1,34 +1,64 @@ import { defineStore } from 'pinia' +import { useCookies } from '@vueuse/integrations/useCookies' +import type { CookieChangeOptions } from 'universal-cookie' -export const useUserStore = defineStore('user', { - state: () => ({ - token: '', - unreadCount: 0, - secureSessionId: '', - passkeyRawId: '', - }), - getters: { - isLogin(state): boolean { - return !!state.token - }, - passkeyLoginAvailable(state): boolean { - return !!state.passkeyRawId - }, - }, - actions: { - passkeyLogin(rawId: string, token: string) { - this.passkeyRawId = rawId - this.login(token) - }, - login(token: string) { - this.token = token - }, - logout() { - this.token = '' - this.passkeyRawId = '' - this.secureSessionId = '' - this.unreadCount = 0 - }, - }, +export const useUserStore = defineStore('user', () => { + const cookies = useCookies(['nginx-ui']) + + const token = ref('') + + watch(token, v => { + cookies.set('token', v, { maxAge: 86400 }) + }) + + const secureSessionId = ref('') + + watch(secureSessionId, v => { + cookies.set('secure_session_id', v, { maxAge: 60 * 3 }) + }) + + function handleCookieChange({ name, value }: CookieChangeOptions) { + if (name === 'token') + token.value = value + else if (name === 'secure_session_id') + secureSessionId.value = value + } + + cookies.addChangeListener(handleCookieChange) + + const passkeyRawId = ref('') + + const unreadCount = ref(0) + const isLogin = computed(() => !!token.value) + const passkeyLoginAvailable = computed(() => !!passkeyRawId.value) + + function passkeyLogin(rawId: string, tokenValue: string) { + passkeyRawId.value = rawId + login(tokenValue) + } + + function login(tokenValue: string) { + token.value = tokenValue + } + + function logout() { + token.value = '' + passkeyRawId.value = '' + secureSessionId.value = '' + unreadCount.value = 0 + } + + return { + token, + unreadCount, + secureSessionId, + passkeyRawId, + isLogin, + passkeyLoginAvailable, + passkeyLogin, + login, + logout, + } +}, { persist: true, }) diff --git a/app/src/views/other/Login.vue b/app/src/views/other/Login.vue index 64c88d7a..1f6782b5 100644 --- a/app/src/views/other/Login.vue +++ b/app/src/views/other/Login.vue @@ -1,7 +1,6 @@ + + + + diff --git a/app/src/views/preference/LogrotateSettings.vue b/app/src/views/preference/LogrotateSettings.vue index 03a188ba..ac4dbd93 100644 --- a/app/src/views/preference/LogrotateSettings.vue +++ b/app/src/views/preference/LogrotateSettings.vue @@ -1,5 +1,5 @@ diff --git a/app/src/views/preference/NginxSettings.vue b/app/src/views/preference/NginxSettings.vue index 513eb9a5..b504d3f0 100644 --- a/app/src/views/preference/NginxSettings.vue +++ b/app/src/views/preference/NginxSettings.vue @@ -1,30 +1,38 @@ diff --git a/app/src/views/preference/OpenAISettings.vue b/app/src/views/preference/OpenAISettings.vue index 18fcee47..5f1bc50b 100644 --- a/app/src/views/preference/OpenAISettings.vue +++ b/app/src/views/preference/OpenAISettings.vue @@ -1,5 +1,5 @@