From e1896f677c65e7a7eb3ea8379027049c99964be8 Mon Sep 17 00:00:00 2001 From: shanshanzhong Date: Fri, 27 Feb 2026 08:49:37 -0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=BC=95=E5=85=A5=E7=AD=BE=E5=90=8D?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E3=80=81=E5=8A=A0=E5=AF=86=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E5=8C=85=E5=8F=8A=E5=A4=A7=E9=87=8Fgoctl=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E6=A8=A1=E6=9D=BF=EF=BC=8C=E5=B9=B6=E6=9B=B4?= =?UTF-8?q?=E6=96=B0API=E3=80=81Admin=E5=92=8CNode=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .goctl/api/handler/handler.tpl | 0 Makefile | 6 +- apps/admin/etc/admin-dev.yaml | 14 ++ apps/admin/etc/admin-prod.yaml | 15 ++ apps/admin/etc/admin-test.yaml | 14 ++ apps/admin/internal/config/config.go | 8 +- .../announcement/createAnnouncementHandler.go | 12 +- .../announcement/deleteAnnouncementHandler.go | 12 +- .../announcement/updateAnnouncementHandler.go | 12 +- .../internal/handler/common/healthHandler.go | 8 +- .../handler/console/getConsoleStatsHandler.go | 8 +- .../handler/order/getOrderListHandler.go | 12 +- .../handler/order/updateOrderStatusHandler.go | 12 +- apps/admin/internal/handler/routes.go | 2 +- .../handler/server/createServerHandler.go | 12 +- .../handler/server/deleteServerHandler.go | 12 +- .../handler/server/getServerListHandler.go | 12 +- .../handler/server/updateServerHandler.go | 12 +- .../subscribe/createSubscribeHandler.go | 12 +- .../subscribe/deleteSubscribeHandler.go | 12 +- .../subscribe/getSubscribeListHandler.go | 12 +- .../subscribe/updateSubscribeHandler.go | 12 +- .../system/getRegisterConfigHandler.go | 8 +- .../handler/system/getSiteConfigHandler.go | 8 +- .../system/updateRegisterConfigHandler.go | 12 +- .../handler/system/updateSiteConfigHandler.go | 12 +- .../ticket/createTicketFollowHandler.go | 12 +- .../handler/ticket/getTicketDetailHandler.go | 12 +- .../handler/ticket/getTicketListHandler.go | 12 +- .../ticket/updateTicketStatusHandler.go | 12 +- .../handler/user/deleteUserHandler.go | 12 +- .../handler/user/getUserDetailHandler.go | 12 +- .../handler/user/getUserListHandler.go | 12 +- .../middleware/signatureMiddleware.go | 88 ++++++++++ apps/admin/internal/svc/serviceContext.go | 12 +- apps/admin/ppaneladmin.go | 1 + apps/api/desc/auth.api | 49 ++++-- apps/api/etc/api-dev.yaml | 18 ++ apps/api/etc/api-prod.yaml | 19 +++ apps/api/etc/api-test.yaml | 18 ++ apps/api/internal/config/config.go | 10 +- .../handler/auth/resetPasswordHandler.go | 14 +- .../internal/handler/auth/userLoginHandler.go | 12 +- .../handler/auth/userRegisterHandler.go | 12 +- .../common/getAnnouncementListHandler.go | 8 +- .../getAvailablePaymentMethodsHandler.go | 8 +- .../common/getDocumentDetailHandler.go | 12 +- .../handler/common/getDocumentListHandler.go | 8 +- .../handler/common/getGlobalConfigHandler.go | 8 +- .../common/getSubscribeGroupListHandler.go | 8 +- .../handler/common/getSubscribeListHandler.go | 8 +- .../internal/handler/common/healthHandler.go | 8 +- .../handler/common/sendEmailCodeHandler.go | 12 +- .../handler/order/closeOrderHandler.go | 12 +- .../handler/order/createOrderHandler.go | 12 +- .../handler/order/getOrderDetailHandler.go | 12 +- apps/api/internal/handler/routes.go | 2 +- .../ticket/createTicketFollowHandler.go | 12 +- .../handler/ticket/createTicketHandler.go | 12 +- .../handler/ticket/getTicketDetailHandler.go | 12 +- .../handler/user/getUserInfoHandler.go | 8 +- .../handler/user/getUserSubscribeHandler.go | 8 +- .../handler/user/updateUserPasswordHandler.go | 12 +- .../internal/logic/auth/resetPasswordLogic.go | 4 +- .../api/internal/logic/auth/userLoginLogic.go | 2 +- .../internal/logic/auth/userRegisterLogic.go | 2 +- apps/api/internal/logic/common/healthLogic.go | 15 +- .../internal/middleware/decryptMiddleware.go | 158 ++++++++++++++++++ .../middleware/signatureMiddleware.go | 83 +++++++++ apps/api/internal/svc/serviceContext.go | 20 ++- apps/api/internal/types/types.go | 42 +++-- apps/api/ppanel.go | 7 + apps/node/etc/node-dev.yaml | 14 ++ apps/node/etc/node-prod.yaml | 15 ++ apps/node/etc/node-test.yaml | 14 ++ apps/node/internal/config/config.go | 9 +- .../internal/handler/common/healthHandler.go | 8 +- .../handler/node/getServerConfigHandler.go | 8 +- .../handler/node/getServerUserListHandler.go | 8 +- .../handler/node/pushOnlineUsersHandler.go | 12 +- .../handler/node/pushStatusHandler.go | 12 +- .../handler/node/pushUserTrafficHandler.go | 12 +- .../middleware/signatureMiddleware.go | 88 ++++++++++ apps/node/internal/svc/serviceContext.go | 15 +- apps/node/ppanelnode.go | 1 + apps/rpc/core/core.proto | 4 + apps/rpc/core/core/core.pb.go | 48 +++++- apps/rpc/core/core/core_grpc.pb.go | 12 +- apps/rpc/core/coreClient/core.go | 2 +- apps/rpc/core/etc/core.yaml | 6 + .../core/internal/logic/getUserInfoLogic.go | 46 ++++- go.mod | 12 +- go.sum | 22 +-- goctl_tpl/api/config.tpl | 12 ++ goctl_tpl/api/context.tpl | 20 +++ goctl_tpl/api/etc.tpl | 3 + goctl_tpl/api/handler.tpl | 26 +++ goctl_tpl/api/handler_test.tpl | 84 ++++++++++ goctl_tpl/api/integration_test.tpl | 120 +++++++++++++ goctl_tpl/api/logic.tpl | 29 ++++ goctl_tpl/api/logic_test.tpl | 72 ++++++++ goctl_tpl/api/main.tpl | 29 ++++ goctl_tpl/api/middleware.tpl | 22 +++ goctl_tpl/api/route-addition.tpl | 4 + goctl_tpl/api/routes.tpl | 15 ++ goctl_tpl/api/sse_handler.tpl | 68 ++++++++ goctl_tpl/api/sse_logic.tpl | 29 ++++ goctl_tpl/api/svc_test.tpl | 60 +++++++ goctl_tpl/api/template.tpl | 24 +++ goctl_tpl/api/types.tpl | 8 + goctl_tpl/docker/docker.tpl | 36 ++++ goctl_tpl/gateway/etc.tpl | 18 ++ goctl_tpl/gateway/main.tpl | 20 +++ goctl_tpl/kube/deployment.tpl | 117 +++++++++++++ goctl_tpl/kube/job.tpl | 37 ++++ goctl_tpl/model/customized.tpl | 0 goctl_tpl/model/delete.tpl | 14 ++ goctl_tpl/model/err.tpl | 5 + goctl_tpl/model/field.tpl | 1 + .../model/find-one-by-field-extra-method.tpl | 8 + goctl_tpl/model/find-one-by-field.tpl | 30 ++++ goctl_tpl/model/find-one.tpl | 26 +++ goctl_tpl/model/import-no-cache.tpl | 14 ++ goctl_tpl/model/import.tpl | 16 ++ goctl_tpl/model/insert.tpl | 9 + goctl_tpl/model/interface-delete.tpl | 1 + .../model/interface-find-one-by-field.tpl | 1 + goctl_tpl/model/interface-find-one.tpl | 1 + goctl_tpl/model/interface-insert.tpl | 1 + goctl_tpl/model/interface-update.tpl | 1 + goctl_tpl/model/model-gen.tpl | 16 ++ goctl_tpl/model/model-new.tpl | 7 + goctl_tpl/model/model.tpl | 38 +++++ goctl_tpl/model/table-name.tpl | 3 + goctl_tpl/model/tag.tpl | 1 + goctl_tpl/model/types.tpl | 14 ++ goctl_tpl/model/update.tpl | 14 ++ goctl_tpl/model/var.tpl | 8 + goctl_tpl/mongo/err.tpl | 12 ++ goctl_tpl/mongo/model.tpl | 79 +++++++++ goctl_tpl/mongo/model_custom.tpl | 38 +++++ goctl_tpl/mongo/model_types.tpl | 14 ++ goctl_tpl/newapi/newtemplate.tpl | 14 ++ goctl_tpl/rpc/call.tpl | 33 ++++ goctl_tpl/rpc/config.tpl | 7 + goctl_tpl/rpc/etc.tpl | 6 + goctl_tpl/rpc/logic-func.tpl | 6 + goctl_tpl/rpc/logic.tpl | 24 +++ goctl_tpl/rpc/main.tpl | 36 ++++ goctl_tpl/rpc/server-func.tpl | 6 + goctl_tpl/rpc/server.tpl | 22 +++ goctl_tpl/rpc/svc.tpl | 13 ++ goctl_tpl/rpc/template.tpl | 16 ++ pkg/cryptox/aes.go | 85 ++++++++++ pkg/cryptox/aes_test.go | 34 ++++ pkg/cryptox/password.go | 15 ++ pkg/result/response.go | 44 +++++ pkg/signature/canonical.go | 51 ++++++ pkg/signature/config.go | 7 + pkg/signature/errors.go | 10 ++ pkg/signature/nonce_store.go | 32 ++++ pkg/signature/signature_test.go | 105 ++++++++++++ pkg/signature/validator.go | 64 +++++++ pkg/xerr/errcode.go | 5 + pkg/xerr/errmsg.go | 12 ++ pkg/xerr/errors.go | 39 +++++ 166 files changed, 2913 insertions(+), 489 deletions(-) create mode 100644 .goctl/api/handler/handler.tpl create mode 100644 apps/admin/internal/middleware/signatureMiddleware.go create mode 100644 apps/api/internal/middleware/decryptMiddleware.go create mode 100644 apps/api/internal/middleware/signatureMiddleware.go create mode 100644 apps/node/internal/middleware/signatureMiddleware.go create mode 100644 apps/rpc/core/etc/core.yaml create mode 100644 goctl_tpl/api/config.tpl create mode 100644 goctl_tpl/api/context.tpl create mode 100644 goctl_tpl/api/etc.tpl create mode 100644 goctl_tpl/api/handler.tpl create mode 100644 goctl_tpl/api/handler_test.tpl create mode 100644 goctl_tpl/api/integration_test.tpl create mode 100644 goctl_tpl/api/logic.tpl create mode 100644 goctl_tpl/api/logic_test.tpl create mode 100644 goctl_tpl/api/main.tpl create mode 100644 goctl_tpl/api/middleware.tpl create mode 100644 goctl_tpl/api/route-addition.tpl create mode 100644 goctl_tpl/api/routes.tpl create mode 100644 goctl_tpl/api/sse_handler.tpl create mode 100644 goctl_tpl/api/sse_logic.tpl create mode 100644 goctl_tpl/api/svc_test.tpl create mode 100644 goctl_tpl/api/template.tpl create mode 100644 goctl_tpl/api/types.tpl create mode 100644 goctl_tpl/docker/docker.tpl create mode 100644 goctl_tpl/gateway/etc.tpl create mode 100644 goctl_tpl/gateway/main.tpl create mode 100644 goctl_tpl/kube/deployment.tpl create mode 100644 goctl_tpl/kube/job.tpl create mode 100644 goctl_tpl/model/customized.tpl create mode 100644 goctl_tpl/model/delete.tpl create mode 100644 goctl_tpl/model/err.tpl create mode 100644 goctl_tpl/model/field.tpl create mode 100644 goctl_tpl/model/find-one-by-field-extra-method.tpl create mode 100644 goctl_tpl/model/find-one-by-field.tpl create mode 100644 goctl_tpl/model/find-one.tpl create mode 100644 goctl_tpl/model/import-no-cache.tpl create mode 100644 goctl_tpl/model/import.tpl create mode 100644 goctl_tpl/model/insert.tpl create mode 100644 goctl_tpl/model/interface-delete.tpl create mode 100644 goctl_tpl/model/interface-find-one-by-field.tpl create mode 100644 goctl_tpl/model/interface-find-one.tpl create mode 100644 goctl_tpl/model/interface-insert.tpl create mode 100644 goctl_tpl/model/interface-update.tpl create mode 100644 goctl_tpl/model/model-gen.tpl create mode 100644 goctl_tpl/model/model-new.tpl create mode 100644 goctl_tpl/model/model.tpl create mode 100644 goctl_tpl/model/table-name.tpl create mode 100644 goctl_tpl/model/tag.tpl create mode 100644 goctl_tpl/model/types.tpl create mode 100644 goctl_tpl/model/update.tpl create mode 100644 goctl_tpl/model/var.tpl create mode 100644 goctl_tpl/mongo/err.tpl create mode 100644 goctl_tpl/mongo/model.tpl create mode 100644 goctl_tpl/mongo/model_custom.tpl create mode 100644 goctl_tpl/mongo/model_types.tpl create mode 100644 goctl_tpl/newapi/newtemplate.tpl create mode 100644 goctl_tpl/rpc/call.tpl create mode 100644 goctl_tpl/rpc/config.tpl create mode 100644 goctl_tpl/rpc/etc.tpl create mode 100644 goctl_tpl/rpc/logic-func.tpl create mode 100644 goctl_tpl/rpc/logic.tpl create mode 100644 goctl_tpl/rpc/main.tpl create mode 100644 goctl_tpl/rpc/server-func.tpl create mode 100644 goctl_tpl/rpc/server.tpl create mode 100644 goctl_tpl/rpc/svc.tpl create mode 100644 goctl_tpl/rpc/template.tpl create mode 100644 pkg/cryptox/aes.go create mode 100644 pkg/cryptox/aes_test.go create mode 100644 pkg/cryptox/password.go create mode 100644 pkg/signature/canonical.go create mode 100644 pkg/signature/config.go create mode 100644 pkg/signature/errors.go create mode 100644 pkg/signature/nonce_store.go create mode 100644 pkg/signature/signature_test.go create mode 100644 pkg/signature/validator.go create mode 100644 pkg/xerr/errors.go diff --git a/.goctl/api/handler/handler.tpl b/.goctl/api/handler/handler.tpl new file mode 100644 index 0000000..e69de29 diff --git a/Makefile b/Makefile index 0accb33..35d360e 100644 --- a/Makefile +++ b/Makefile @@ -47,9 +47,9 @@ run-rpc-core: # Code generation gen-api: - cd apps/api && goctl api go -api api.api -dir . -style goZero - cd apps/admin && goctl api go -api admin.api -dir . -style goZero - cd apps/node && goctl api go -api node.api -dir . -style goZero + cd apps/api && goctl api go -api api.api -dir . -style goZero -home ../../goctl_tpl + cd apps/admin && goctl api go -api admin.api -dir . -style goZero -home ../../goctl_tpl + cd apps/node && goctl api go -api node.api -dir . -style goZero -home ../../goctl_tpl # fix: admin routes.go 中 server 包名与参数名 server(*rest.Server) 冲突 # 1. 若 goctl 生成了 server import 但没加别名,加上别名 sed -i '' 's|"github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/server"|serverhandler "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/server"|g' apps/admin/internal/handler/routes.go diff --git a/apps/admin/etc/admin-dev.yaml b/apps/admin/etc/admin-dev.yaml index 23cbac5..2b41fe3 100644 --- a/apps/admin/etc/admin-dev.yaml +++ b/apps/admin/etc/admin-dev.yaml @@ -30,3 +30,17 @@ MySQL: Redis: Host: 127.0.0.1:6379 Type: node + +CacheRedis: + Host: 127.0.0.1:6379 + Type: node + +AppSignature: + AppSecrets: + android-client: "uB4G,XxL2{7b" + web-client: "uB4G,XxL2{7b" + ios-client: "uB4G,XxL2{7b" + mac-client: "uB4G,XxL2{7b" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/admin/health diff --git a/apps/admin/etc/admin-prod.yaml b/apps/admin/etc/admin-prod.yaml index c8a26ac..fa783d6 100644 --- a/apps/admin/etc/admin-prod.yaml +++ b/apps/admin/etc/admin-prod.yaml @@ -34,3 +34,18 @@ Redis: Host: "${REDIS_HOST}" Type: node Pass: "${REDIS_PASS}" + +CacheRedis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +AppSignature: + AppSecrets: + android-client: "${APP_SECRET}" + web-client: "${APP_SECRET}" + ios-client: "${APP_SECRET}" + mac-client: "${APP_SECRET}" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/admin/health diff --git a/apps/admin/etc/admin-test.yaml b/apps/admin/etc/admin-test.yaml index 6e5314d..cb682ac 100644 --- a/apps/admin/etc/admin-test.yaml +++ b/apps/admin/etc/admin-test.yaml @@ -32,3 +32,17 @@ MySQL: Redis: Host: redis:6379 Type: node + +CacheRedis: + Host: redis:6379 + Type: node + +AppSignature: + AppSecrets: + android-client: "uB4G,XxL2{7b" + web-client: "uB4G,XxL2{7b" + ios-client: "uB4G,XxL2{7b" + mac-client: "uB4G,XxL2{7b" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/admin/health diff --git a/apps/admin/internal/config/config.go b/apps/admin/internal/config/config.go index 0f318cd..f305aaf 100644 --- a/apps/admin/internal/config/config.go +++ b/apps/admin/internal/config/config.go @@ -3,7 +3,11 @@ package config -import "github.com/zeromicro/go-zero/rest" +import ( + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zeromicro/go-zero/core/stores/redis" + "github.com/zeromicro/go-zero/rest" +) type Config struct { rest.RestConf @@ -11,4 +15,6 @@ type Config struct { AccessSecret string AccessExpire int64 } + CacheRedis redis.RedisConf + AppSignature signature.SignatureConf } diff --git a/apps/admin/internal/handler/announcement/createAnnouncementHandler.go b/apps/admin/internal/handler/announcement/createAnnouncementHandler.go index 9c4e995..743d11e 100644 --- a/apps/admin/internal/handler/announcement/createAnnouncementHandler.go +++ b/apps/admin/internal/handler/announcement/createAnnouncementHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/announcement" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CreateAnnouncementHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.CreateAnnouncementReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := announcement.NewCreateAnnouncementLogic(r.Context(), svcCtx) resp, err := l.CreateAnnouncement(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/announcement/deleteAnnouncementHandler.go b/apps/admin/internal/handler/announcement/deleteAnnouncementHandler.go index 91f623d..2019ea9 100644 --- a/apps/admin/internal/handler/announcement/deleteAnnouncementHandler.go +++ b/apps/admin/internal/handler/announcement/deleteAnnouncementHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/announcement" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func DeleteAnnouncementHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.DeleteAnnouncementReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := announcement.NewDeleteAnnouncementLogic(r.Context(), svcCtx) err := l.DeleteAnnouncement(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/announcement/updateAnnouncementHandler.go b/apps/admin/internal/handler/announcement/updateAnnouncementHandler.go index bdcfa33..bf7e0b4 100644 --- a/apps/admin/internal/handler/announcement/updateAnnouncementHandler.go +++ b/apps/admin/internal/handler/announcement/updateAnnouncementHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/announcement" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateAnnouncementHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UpdateAnnouncementReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := announcement.NewUpdateAnnouncementLogic(r.Context(), svcCtx) err := l.UpdateAnnouncement(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/common/healthHandler.go b/apps/admin/internal/handler/common/healthHandler.go index 7fd6574..d4a9bed 100644 --- a/apps/admin/internal/handler/common/healthHandler.go +++ b/apps/admin/internal/handler/common/healthHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func HealthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewHealthLogic(r.Context(), svcCtx) resp, err := l.Health() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/console/getConsoleStatsHandler.go b/apps/admin/internal/handler/console/getConsoleStatsHandler.go index 3bba2b2..19b53b4 100644 --- a/apps/admin/internal/handler/console/getConsoleStatsHandler.go +++ b/apps/admin/internal/handler/console/getConsoleStatsHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/console" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetConsoleStatsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := console.NewGetConsoleStatsLogic(r.Context(), svcCtx) resp, err := l.GetConsoleStats() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/order/getOrderListHandler.go b/apps/admin/internal/handler/order/getOrderListHandler.go index 532336b..75afd0a 100644 --- a/apps/admin/internal/handler/order/getOrderListHandler.go +++ b/apps/admin/internal/handler/order/getOrderListHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/order" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetOrderListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminOrderListReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := order.NewGetOrderListLogic(r.Context(), svcCtx) resp, err := l.GetOrderList(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/order/updateOrderStatusHandler.go b/apps/admin/internal/handler/order/updateOrderStatusHandler.go index 248cd55..202ad33 100644 --- a/apps/admin/internal/handler/order/updateOrderStatusHandler.go +++ b/apps/admin/internal/handler/order/updateOrderStatusHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/order" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateOrderStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UpdateOrderStatusReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := order.NewUpdateOrderStatusLogic(r.Context(), svcCtx) err := l.UpdateOrderStatus(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/routes.go b/apps/admin/internal/handler/routes.go index 5d0c158..2e5d3f4 100644 --- a/apps/admin/internal/handler/routes.go +++ b/apps/admin/internal/handler/routes.go @@ -10,7 +10,7 @@ import ( common "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/common" console "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/console" order "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/order" - serverhandler "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/server" + server serverhandler "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/server" subscribe "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/subscribe" system "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/system" ticket "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/handler/ticket" diff --git a/apps/admin/internal/handler/server/createServerHandler.go b/apps/admin/internal/handler/server/createServerHandler.go index 5af836f..7dc0118 100644 --- a/apps/admin/internal/handler/server/createServerHandler.go +++ b/apps/admin/internal/handler/server/createServerHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/server" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CreateServerHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.CreateServerReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := server.NewCreateServerLogic(r.Context(), svcCtx) resp, err := l.CreateServer(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/server/deleteServerHandler.go b/apps/admin/internal/handler/server/deleteServerHandler.go index d106e3c..0060287 100644 --- a/apps/admin/internal/handler/server/deleteServerHandler.go +++ b/apps/admin/internal/handler/server/deleteServerHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/server" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func DeleteServerHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.DeleteServerReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := server.NewDeleteServerLogic(r.Context(), svcCtx) err := l.DeleteServer(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/server/getServerListHandler.go b/apps/admin/internal/handler/server/getServerListHandler.go index 6306b3d..0afb025 100644 --- a/apps/admin/internal/handler/server/getServerListHandler.go +++ b/apps/admin/internal/handler/server/getServerListHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/server" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetServerListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.ServerListReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := server.NewGetServerListLogic(r.Context(), svcCtx) resp, err := l.GetServerList(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/server/updateServerHandler.go b/apps/admin/internal/handler/server/updateServerHandler.go index 5ba9d54..b754793 100644 --- a/apps/admin/internal/handler/server/updateServerHandler.go +++ b/apps/admin/internal/handler/server/updateServerHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/server" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateServerHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UpdateServerReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := server.NewUpdateServerLogic(r.Context(), svcCtx) err := l.UpdateServer(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/subscribe/createSubscribeHandler.go b/apps/admin/internal/handler/subscribe/createSubscribeHandler.go index 557cc2e..ab23d89 100644 --- a/apps/admin/internal/handler/subscribe/createSubscribeHandler.go +++ b/apps/admin/internal/handler/subscribe/createSubscribeHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/subscribe" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CreateSubscribeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.CreateSubscribeReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := subscribe.NewCreateSubscribeLogic(r.Context(), svcCtx) resp, err := l.CreateSubscribe(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/subscribe/deleteSubscribeHandler.go b/apps/admin/internal/handler/subscribe/deleteSubscribeHandler.go index 191e7f9..b802985 100644 --- a/apps/admin/internal/handler/subscribe/deleteSubscribeHandler.go +++ b/apps/admin/internal/handler/subscribe/deleteSubscribeHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/subscribe" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func DeleteSubscribeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.DeleteSubscribeReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := subscribe.NewDeleteSubscribeLogic(r.Context(), svcCtx) err := l.DeleteSubscribe(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/subscribe/getSubscribeListHandler.go b/apps/admin/internal/handler/subscribe/getSubscribeListHandler.go index 9d6d1cb..00874f4 100644 --- a/apps/admin/internal/handler/subscribe/getSubscribeListHandler.go +++ b/apps/admin/internal/handler/subscribe/getSubscribeListHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/subscribe" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetSubscribeListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminSubscribeListReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := subscribe.NewGetSubscribeListLogic(r.Context(), svcCtx) resp, err := l.GetSubscribeList(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/subscribe/updateSubscribeHandler.go b/apps/admin/internal/handler/subscribe/updateSubscribeHandler.go index 48d0ca8..23d90a4 100644 --- a/apps/admin/internal/handler/subscribe/updateSubscribeHandler.go +++ b/apps/admin/internal/handler/subscribe/updateSubscribeHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/subscribe" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateSubscribeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UpdateSubscribeReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := subscribe.NewUpdateSubscribeLogic(r.Context(), svcCtx) err := l.UpdateSubscribe(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/system/getRegisterConfigHandler.go b/apps/admin/internal/handler/system/getRegisterConfigHandler.go index 0908d53..ab5ce21 100644 --- a/apps/admin/internal/handler/system/getRegisterConfigHandler.go +++ b/apps/admin/internal/handler/system/getRegisterConfigHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/system" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetRegisterConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := system.NewGetRegisterConfigLogic(r.Context(), svcCtx) resp, err := l.GetRegisterConfig() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/system/getSiteConfigHandler.go b/apps/admin/internal/handler/system/getSiteConfigHandler.go index e09a93a..c7e831e 100644 --- a/apps/admin/internal/handler/system/getSiteConfigHandler.go +++ b/apps/admin/internal/handler/system/getSiteConfigHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/system" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetSiteConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := system.NewGetSiteConfigLogic(r.Context(), svcCtx) resp, err := l.GetSiteConfig() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/system/updateRegisterConfigHandler.go b/apps/admin/internal/handler/system/updateRegisterConfigHandler.go index e93286c..5191671 100644 --- a/apps/admin/internal/handler/system/updateRegisterConfigHandler.go +++ b/apps/admin/internal/handler/system/updateRegisterConfigHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/system" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateRegisterConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UpdateRegisterConfigReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := system.NewUpdateRegisterConfigLogic(r.Context(), svcCtx) err := l.UpdateRegisterConfig(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/system/updateSiteConfigHandler.go b/apps/admin/internal/handler/system/updateSiteConfigHandler.go index 0ef4c1c..306b608 100644 --- a/apps/admin/internal/handler/system/updateSiteConfigHandler.go +++ b/apps/admin/internal/handler/system/updateSiteConfigHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/system" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateSiteConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UpdateSiteConfigReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := system.NewUpdateSiteConfigLogic(r.Context(), svcCtx) err := l.UpdateSiteConfig(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/ticket/createTicketFollowHandler.go b/apps/admin/internal/handler/ticket/createTicketFollowHandler.go index 95e97e1..218f992 100644 --- a/apps/admin/internal/handler/ticket/createTicketFollowHandler.go +++ b/apps/admin/internal/handler/ticket/createTicketFollowHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/ticket" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CreateTicketFollowHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminCreateTicketFollowReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := ticket.NewCreateTicketFollowLogic(r.Context(), svcCtx) err := l.CreateTicketFollow(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/ticket/getTicketDetailHandler.go b/apps/admin/internal/handler/ticket/getTicketDetailHandler.go index 941ded1..86b41d6 100644 --- a/apps/admin/internal/handler/ticket/getTicketDetailHandler.go +++ b/apps/admin/internal/handler/ticket/getTicketDetailHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/ticket" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetTicketDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminTicketDetailReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := ticket.NewGetTicketDetailLogic(r.Context(), svcCtx) resp, err := l.GetTicketDetail(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/ticket/getTicketListHandler.go b/apps/admin/internal/handler/ticket/getTicketListHandler.go index 1933051..3667906 100644 --- a/apps/admin/internal/handler/ticket/getTicketListHandler.go +++ b/apps/admin/internal/handler/ticket/getTicketListHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/ticket" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetTicketListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminTicketListReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := ticket.NewGetTicketListLogic(r.Context(), svcCtx) resp, err := l.GetTicketList(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/ticket/updateTicketStatusHandler.go b/apps/admin/internal/handler/ticket/updateTicketStatusHandler.go index 756b91c..354dd9c 100644 --- a/apps/admin/internal/handler/ticket/updateTicketStatusHandler.go +++ b/apps/admin/internal/handler/ticket/updateTicketStatusHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/ticket" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateTicketStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminUpdateTicketStatusReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := ticket.NewUpdateTicketStatusLogic(r.Context(), svcCtx) err := l.UpdateTicketStatus(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/user/deleteUserHandler.go b/apps/admin/internal/handler/user/deleteUserHandler.go index e692866..7986871 100644 --- a/apps/admin/internal/handler/user/deleteUserHandler.go +++ b/apps/admin/internal/handler/user/deleteUserHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/user" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func DeleteUserHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminDeleteUserReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := user.NewDeleteUserLogic(r.Context(), svcCtx) err := l.DeleteUser(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/admin/internal/handler/user/getUserDetailHandler.go b/apps/admin/internal/handler/user/getUserDetailHandler.go index 1a97765..970aaa8 100644 --- a/apps/admin/internal/handler/user/getUserDetailHandler.go +++ b/apps/admin/internal/handler/user/getUserDetailHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/user" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetUserDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminUserDetailReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := user.NewGetUserDetailLogic(r.Context(), svcCtx) resp, err := l.GetUserDetail(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/handler/user/getUserListHandler.go b/apps/admin/internal/handler/user/getUserListHandler.go index bafd59a..f28493b 100644 --- a/apps/admin/internal/handler/user/getUserListHandler.go +++ b/apps/admin/internal/handler/user/getUserListHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/logic/user" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetUserListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.AdminUserListReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := user.NewGetUserListLogic(r.Context(), svcCtx) resp, err := l.GetUserList(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/admin/internal/middleware/signatureMiddleware.go b/apps/admin/internal/middleware/signatureMiddleware.go new file mode 100644 index 0000000..1788843 --- /dev/null +++ b/apps/admin/internal/middleware/signatureMiddleware.go @@ -0,0 +1,88 @@ +package middleware + +import ( + "bytes" + "io" + "net/http" + "strings" + + "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/config" + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zero-ppanel/zero-ppanel/pkg/xerr" + "github.com/zeromicro/go-zero/rest/httpx" +) + +type SignatureMiddleware struct { + conf config.Config + validator *signature.Validator +} + +func NewSignatureMiddleware(c config.Config, store signature.NonceStore) *SignatureMiddleware { + return &SignatureMiddleware{ + conf: c, + validator: signature.NewValidator(c.AppSignature, store), + } +} + +func (m *SignatureMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + appId := r.Header.Get("X-App-Id") + if appId == "" { + next(w, r) + return + } + + for _, prefix := range m.conf.AppSignature.SkipPrefixes { + if strings.HasPrefix(r.URL.Path, prefix) { + next(w, r) + return + } + } + + timestamp := r.Header.Get("X-Timestamp") + nonce := r.Header.Get("X-Nonce") + sig := r.Header.Get("X-Signature") + + if timestamp == "" || nonce == "" || sig == "" { + httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(xerr.SignatureMissing)) + return + } + + var bodyBytes []byte + if r.Body != nil { + bodyBytes, _ = io.ReadAll(r.Body) + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } + + sts := signature.BuildStringToSign(r.Method, r.URL.Path, r.URL.RawQuery, bodyBytes, appId, timestamp, nonce) + + if err := m.validator.Validate(r.Context(), appId, timestamp, nonce, sig, sts); err != nil { + code := mapSignatureErr(err) + httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(code)) + return + } + + next(w, r) + } +} + +func mapSignatureErr(err error) int { + switch err { + case signature.ErrSignatureMissing: + return xerr.SignatureMissing + case signature.ErrSignatureExpired: + return xerr.SignatureExpired + case signature.ErrSignatureReplay: + return xerr.SignatureReplay + default: + return xerr.SignatureInvalid + } +} + +func buildErrResp(code int) map[string]interface{} { + return map[string]interface{}{ + "code": code, + "msg": xerr.MapErrMsg(code), + "data": nil, + } +} diff --git a/apps/admin/internal/svc/serviceContext.go b/apps/admin/internal/svc/serviceContext.go index e832358..8c498c7 100644 --- a/apps/admin/internal/svc/serviceContext.go +++ b/apps/admin/internal/svc/serviceContext.go @@ -5,14 +5,22 @@ package svc import ( "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/config" + "github.com/zero-ppanel/zero-ppanel/apps/admin/internal/middleware" + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zeromicro/go-zero/core/stores/redis" ) type ServiceContext struct { - Config config.Config + Config config.Config + SignatureMiddleware *middleware.SignatureMiddleware } func NewServiceContext(c config.Config) *ServiceContext { + rds := redis.MustNewRedis(c.CacheRedis) + nonceStore := signature.NewRedisNonceStore(rds) + return &ServiceContext{ - Config: c, + Config: c, + SignatureMiddleware: middleware.NewSignatureMiddleware(c, nonceStore), } } diff --git a/apps/admin/ppaneladmin.go b/apps/admin/ppaneladmin.go index 9654f8f..c7f599a 100644 --- a/apps/admin/ppaneladmin.go +++ b/apps/admin/ppaneladmin.go @@ -27,6 +27,7 @@ func main() { defer server.Stop() ctx := svc.NewServiceContext(c) + server.Use(ctx.SignatureMiddleware.Handle) handler.RegisterHandlers(server, ctx) fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) diff --git a/apps/api/desc/auth.api b/apps/api/desc/auth.api index d3786bd..fb3e7fc 100644 --- a/apps/api/desc/auth.api +++ b/apps/api/desc/auth.api @@ -6,26 +6,40 @@ info ( type ( UserLoginReq { - Email string `json:"email"` - Password string `json:"password"` + Identifier string `json:"identifier"` + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + IP string `header:"X-Original-Forwarded-For,optional"` + UserAgent string `header:"User-Agent,optional"` + LoginType string `header:"Login-Type,optional"` + CfToken string `json:"cf_token,optional"` + } + + LoginResp { + Token string `json:"token"` } UserRegisterReq { - Email string `json:"email"` - Password string `json:"password"` - Code string `json:"code"` - ReferCode string `json:"refer_code,optional"` - } - - AuthResp { - Token string `json:"token"` - Expire int64 `json:"expire"` + Identifier string `json:"identifier"` + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + Invite string `json:"invite,optional"` + Code string `json:"code,optional"` + IP string `header:"X-Original-Forwarded-For,optional"` + UserAgent string `header:"User-Agent,optional"` + LoginType string `header:"Login-Type,optional"` + CfToken string `json:"cf_token,optional"` } ResetPasswordReq { - Email string `json:"email"` - Password string `json:"password"` - Code string `json:"code"` + Identifier string `json:"identifier"` + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + Code string `json:"code,optional"` + IP string `header:"X-Original-Forwarded-For,optional"` + UserAgent string `header:"User-Agent,optional"` + LoginType string `header:"Login-Type,optional"` + CfToken string `json:"cf_token,optional"` } ) @@ -35,11 +49,12 @@ type ( ) service ppanel-api { @handler UserLoginHandler - post /login (UserLoginReq) returns (AuthResp) + post /login (UserLoginReq) returns (LoginResp) @handler UserRegisterHandler - post /register (UserRegisterReq) returns (AuthResp) + post /register (UserRegisterReq) returns (LoginResp) @handler ResetPasswordHandler - post /reset_password (ResetPasswordReq) + post /reset (ResetPasswordReq) returns (LoginResp) + } diff --git a/apps/api/etc/api-dev.yaml b/apps/api/etc/api-dev.yaml index 3d597e9..b1f80bf 100644 --- a/apps/api/etc/api-dev.yaml +++ b/apps/api/etc/api-dev.yaml @@ -31,6 +31,24 @@ Redis: Host: 127.0.0.1:6379 Type: node +CacheRedis: + Host: 127.0.0.1:6379 + Type: node + +AppSignature: + AppSecrets: + android-client: "uB4G,XxL2{7b" + web-client: "uB4G,XxL2{7b" + ios-client: "uB4G,XxL2{7b" + mac-client: "uB4G,XxL2{7b" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/health + +Security: + Enable: true + SecuritySecret: "uB4G,XxL2{7b" + Asynq: Addr: 127.0.0.1:6379 diff --git a/apps/api/etc/api-prod.yaml b/apps/api/etc/api-prod.yaml index d102877..5e04a3b 100644 --- a/apps/api/etc/api-prod.yaml +++ b/apps/api/etc/api-prod.yaml @@ -35,6 +35,25 @@ Redis: Type: node Pass: "${REDIS_PASS}" +CacheRedis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +AppSignature: + AppSecrets: + android-client: "${APP_SECRET}" + web-client: "${APP_SECRET}" + ios-client: "${APP_SECRET}" + mac-client: "${APP_SECRET}" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/health + +Security: + Enable: true + SecuritySecret: "${SECURITY_SECRET}" + Asynq: Addr: "${REDIS_HOST}" Pass: "${REDIS_PASS}" diff --git a/apps/api/etc/api-test.yaml b/apps/api/etc/api-test.yaml index 8d4d9e4..c9e74a5 100644 --- a/apps/api/etc/api-test.yaml +++ b/apps/api/etc/api-test.yaml @@ -33,5 +33,23 @@ Redis: Host: redis:6379 Type: node +CacheRedis: + Host: redis:6379 + Type: node + +AppSignature: + AppSecrets: + android-client: "uB4G,XxL2{7b" + web-client: "uB4G,XxL2{7b" + ios-client: "uB4G,XxL2{7b" + mac-client: "uB4G,XxL2{7b" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/health + +Security: + Enable: true + SecuritySecret: "uB4G,XxL2{7b" + Asynq: Addr: redis:6379 diff --git a/apps/api/internal/config/config.go b/apps/api/internal/config/config.go index e0e4923..862b3ce 100644 --- a/apps/api/internal/config/config.go +++ b/apps/api/internal/config/config.go @@ -4,6 +4,8 @@ package config import ( + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/rest" "github.com/zeromicro/go-zero/zrpc" ) @@ -14,5 +16,11 @@ type Config struct { AccessSecret string AccessExpire int64 } - CoreRpc zrpc.RpcClientConf + CoreRpc zrpc.RpcClientConf + CacheRedis redis.RedisConf + AppSignature signature.SignatureConf + Security struct { + Enable bool + SecuritySecret string + } } diff --git a/apps/api/internal/handler/auth/resetPasswordHandler.go b/apps/api/internal/handler/auth/resetPasswordHandler.go index 105ca78..804e42f 100644 --- a/apps/api/internal/handler/auth/resetPasswordHandler.go +++ b/apps/api/internal/handler/auth/resetPasswordHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/auth" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func ResetPasswordHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.ResetPasswordReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := auth.NewResetPasswordLogic(r.Context(), svcCtx) - err := l.ResetPassword(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + resp, err := l.ResetPassword(&req) + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/auth/userLoginHandler.go b/apps/api/internal/handler/auth/userLoginHandler.go index a4f09f7..efacb65 100644 --- a/apps/api/internal/handler/auth/userLoginHandler.go +++ b/apps/api/internal/handler/auth/userLoginHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/auth" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UserLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UserLoginReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := auth.NewUserLoginLogic(r.Context(), svcCtx) resp, err := l.UserLogin(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/auth/userRegisterHandler.go b/apps/api/internal/handler/auth/userRegisterHandler.go index 8302187..b4df661 100644 --- a/apps/api/internal/handler/auth/userRegisterHandler.go +++ b/apps/api/internal/handler/auth/userRegisterHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/auth" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UserRegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UserRegisterReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := auth.NewUserRegisterLogic(r.Context(), svcCtx) resp, err := l.UserRegister(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/getAnnouncementListHandler.go b/apps/api/internal/handler/common/getAnnouncementListHandler.go index 12c049a..2bf58bc 100644 --- a/apps/api/internal/handler/common/getAnnouncementListHandler.go +++ b/apps/api/internal/handler/common/getAnnouncementListHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetAnnouncementListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewGetAnnouncementListLogic(r.Context(), svcCtx) resp, err := l.GetAnnouncementList() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/getAvailablePaymentMethodsHandler.go b/apps/api/internal/handler/common/getAvailablePaymentMethodsHandler.go index 85c6039..07e2992 100644 --- a/apps/api/internal/handler/common/getAvailablePaymentMethodsHandler.go +++ b/apps/api/internal/handler/common/getAvailablePaymentMethodsHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetAvailablePaymentMethodsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewGetAvailablePaymentMethodsLogic(r.Context(), svcCtx) resp, err := l.GetAvailablePaymentMethods() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/getDocumentDetailHandler.go b/apps/api/internal/handler/common/getDocumentDetailHandler.go index a229368..02b1ec7 100644 --- a/apps/api/internal/handler/common/getDocumentDetailHandler.go +++ b/apps/api/internal/handler/common/getDocumentDetailHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetDocumentDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.DocumentDetailReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := common.NewGetDocumentDetailLogic(r.Context(), svcCtx) resp, err := l.GetDocumentDetail(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/getDocumentListHandler.go b/apps/api/internal/handler/common/getDocumentListHandler.go index 7afec5a..91f0744 100644 --- a/apps/api/internal/handler/common/getDocumentListHandler.go +++ b/apps/api/internal/handler/common/getDocumentListHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetDocumentListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewGetDocumentListLogic(r.Context(), svcCtx) resp, err := l.GetDocumentList() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/getGlobalConfigHandler.go b/apps/api/internal/handler/common/getGlobalConfigHandler.go index 4265635..98d7be0 100644 --- a/apps/api/internal/handler/common/getGlobalConfigHandler.go +++ b/apps/api/internal/handler/common/getGlobalConfigHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetGlobalConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewGetGlobalConfigLogic(r.Context(), svcCtx) resp, err := l.GetGlobalConfig() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/getSubscribeGroupListHandler.go b/apps/api/internal/handler/common/getSubscribeGroupListHandler.go index 8fc9391..e17c3d8 100644 --- a/apps/api/internal/handler/common/getSubscribeGroupListHandler.go +++ b/apps/api/internal/handler/common/getSubscribeGroupListHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetSubscribeGroupListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewGetSubscribeGroupListLogic(r.Context(), svcCtx) resp, err := l.GetSubscribeGroupList() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/getSubscribeListHandler.go b/apps/api/internal/handler/common/getSubscribeListHandler.go index 3767889..db34afc 100644 --- a/apps/api/internal/handler/common/getSubscribeListHandler.go +++ b/apps/api/internal/handler/common/getSubscribeListHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetSubscribeListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewGetSubscribeListLogic(r.Context(), svcCtx) resp, err := l.GetSubscribeList() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/healthHandler.go b/apps/api/internal/handler/common/healthHandler.go index e0f35f5..b3f1977 100644 --- a/apps/api/internal/handler/common/healthHandler.go +++ b/apps/api/internal/handler/common/healthHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func HealthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewHealthLogic(r.Context(), svcCtx) resp, err := l.Health() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/common/sendEmailCodeHandler.go b/apps/api/internal/handler/common/sendEmailCodeHandler.go index 997f50e..c532f18 100644 --- a/apps/api/internal/handler/common/sendEmailCodeHandler.go +++ b/apps/api/internal/handler/common/sendEmailCodeHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func SendEmailCodeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.SendEmailCodeReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := common.NewSendEmailCodeLogic(r.Context(), svcCtx) err := l.SendEmailCode(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/api/internal/handler/order/closeOrderHandler.go b/apps/api/internal/handler/order/closeOrderHandler.go index c271146..f5551aa 100644 --- a/apps/api/internal/handler/order/closeOrderHandler.go +++ b/apps/api/internal/handler/order/closeOrderHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/order" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CloseOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.CloseOrderReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := order.NewCloseOrderLogic(r.Context(), svcCtx) err := l.CloseOrder(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/api/internal/handler/order/createOrderHandler.go b/apps/api/internal/handler/order/createOrderHandler.go index e635eda..1e86330 100644 --- a/apps/api/internal/handler/order/createOrderHandler.go +++ b/apps/api/internal/handler/order/createOrderHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/order" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CreateOrderHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.CreateOrderReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := order.NewCreateOrderLogic(r.Context(), svcCtx) resp, err := l.CreateOrder(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/order/getOrderDetailHandler.go b/apps/api/internal/handler/order/getOrderDetailHandler.go index 40f8154..fdcd13d 100644 --- a/apps/api/internal/handler/order/getOrderDetailHandler.go +++ b/apps/api/internal/handler/order/getOrderDetailHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/order" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetOrderDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.OrderDetailReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := order.NewGetOrderDetailLogic(r.Context(), svcCtx) resp, err := l.GetOrderDetail(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/routes.go b/apps/api/internal/handler/routes.go index 19d0a5d..abe2fca 100644 --- a/apps/api/internal/handler/routes.go +++ b/apps/api/internal/handler/routes.go @@ -31,7 +31,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { }, { Method: http.MethodPost, - Path: "/reset_password", + Path: "/reset", Handler: auth.ResetPasswordHandler(serverCtx), }, }, diff --git a/apps/api/internal/handler/ticket/createTicketFollowHandler.go b/apps/api/internal/handler/ticket/createTicketFollowHandler.go index 20b09c6..f3f1f01 100644 --- a/apps/api/internal/handler/ticket/createTicketFollowHandler.go +++ b/apps/api/internal/handler/ticket/createTicketFollowHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/ticket" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CreateTicketFollowHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.CreateTicketFollowReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := ticket.NewCreateTicketFollowLogic(r.Context(), svcCtx) err := l.CreateTicketFollow(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/api/internal/handler/ticket/createTicketHandler.go b/apps/api/internal/handler/ticket/createTicketHandler.go index 6d81973..53832b9 100644 --- a/apps/api/internal/handler/ticket/createTicketHandler.go +++ b/apps/api/internal/handler/ticket/createTicketHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/ticket" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func CreateTicketHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.CreateTicketReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := ticket.NewCreateTicketLogic(r.Context(), svcCtx) resp, err := l.CreateTicket(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/ticket/getTicketDetailHandler.go b/apps/api/internal/handler/ticket/getTicketDetailHandler.go index a083181..442e235 100644 --- a/apps/api/internal/handler/ticket/getTicketDetailHandler.go +++ b/apps/api/internal/handler/ticket/getTicketDetailHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/ticket" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetTicketDetailHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.TicketDetailReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := ticket.NewGetTicketDetailLogic(r.Context(), svcCtx) resp, err := l.GetTicketDetail(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/user/getUserInfoHandler.go b/apps/api/internal/handler/user/getUserInfoHandler.go index 12fd457..6c06242 100644 --- a/apps/api/internal/handler/user/getUserInfoHandler.go +++ b/apps/api/internal/handler/user/getUserInfoHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/user" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetUserInfoHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := user.NewGetUserInfoLogic(r.Context(), svcCtx) resp, err := l.GetUserInfo() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/user/getUserSubscribeHandler.go b/apps/api/internal/handler/user/getUserSubscribeHandler.go index 9e8109a..b1dd145 100644 --- a/apps/api/internal/handler/user/getUserSubscribeHandler.go +++ b/apps/api/internal/handler/user/getUserSubscribeHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/user" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetUserSubscribeHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := user.NewGetUserSubscribeLogic(r.Context(), svcCtx) resp, err := l.GetUserSubscribe() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/api/internal/handler/user/updateUserPasswordHandler.go b/apps/api/internal/handler/user/updateUserPasswordHandler.go index 10768af..528e107 100644 --- a/apps/api/internal/handler/user/updateUserPasswordHandler.go +++ b/apps/api/internal/handler/user/updateUserPasswordHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/logic/user" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func UpdateUserPasswordHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.UpdatePasswordReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := user.NewUpdateUserPasswordLogic(r.Context(), svcCtx) err := l.UpdateUserPassword(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/api/internal/logic/auth/resetPasswordLogic.go b/apps/api/internal/logic/auth/resetPasswordLogic.go index d1a61a8..f9e26d6 100644 --- a/apps/api/internal/logic/auth/resetPasswordLogic.go +++ b/apps/api/internal/logic/auth/resetPasswordLogic.go @@ -26,8 +26,8 @@ func NewResetPasswordLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Res } } -func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordReq) error { +func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordReq) (resp *types.LoginResp, err error) { // todo: add your logic here and delete this line - return nil + return } diff --git a/apps/api/internal/logic/auth/userLoginLogic.go b/apps/api/internal/logic/auth/userLoginLogic.go index c756013..68b16fb 100644 --- a/apps/api/internal/logic/auth/userLoginLogic.go +++ b/apps/api/internal/logic/auth/userLoginLogic.go @@ -26,7 +26,7 @@ func NewUserLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UserLog } } -func (l *UserLoginLogic) UserLogin(req *types.UserLoginReq) (resp *types.AuthResp, err error) { +func (l *UserLoginLogic) UserLogin(req *types.UserLoginReq) (resp *types.LoginResp, err error) { // todo: add your logic here and delete this line return diff --git a/apps/api/internal/logic/auth/userRegisterLogic.go b/apps/api/internal/logic/auth/userRegisterLogic.go index 32f7eee..fc13117 100644 --- a/apps/api/internal/logic/auth/userRegisterLogic.go +++ b/apps/api/internal/logic/auth/userRegisterLogic.go @@ -26,7 +26,7 @@ func NewUserRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *User } } -func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterReq) (resp *types.AuthResp, err error) { +func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterReq) (resp *types.LoginResp, err error) { // todo: add your logic here and delete this line return diff --git a/apps/api/internal/logic/common/healthLogic.go b/apps/api/internal/logic/common/healthLogic.go index 72824f3..0179a3f 100644 --- a/apps/api/internal/logic/common/healthLogic.go +++ b/apps/api/internal/logic/common/healthLogic.go @@ -8,7 +8,6 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/types" - "github.com/zero-ppanel/zero-ppanel/apps/rpc/core/core" "github.com/zeromicro/go-zero/core/logx" ) @@ -28,17 +27,7 @@ func NewHealthLogic(ctx context.Context, svcCtx *svc.ServiceContext) *HealthLogi } func (l *HealthLogic) Health() (resp *types.HealthResp, err error) { - // 调用 RPC 进行 Ping 测试,这能触发全链路追踪 (API -> RPC) - rpcResp, err := l.svcCtx.CoreRpc.Ping(l.ctx, &core.Empty{}) + // todo: add your logic here and delete this line - status := "ok" - if err != nil { - status = "rpc_error: " + err.Error() - } else if rpcResp.Msg != "" { - status = rpcResp.Msg - } - - return &types.HealthResp{ - Status: status, - }, nil + return } diff --git a/apps/api/internal/middleware/decryptMiddleware.go b/apps/api/internal/middleware/decryptMiddleware.go new file mode 100644 index 0000000..973bb77 --- /dev/null +++ b/apps/api/internal/middleware/decryptMiddleware.go @@ -0,0 +1,158 @@ +package middleware + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "strings" + + "github.com/zero-ppanel/zero-ppanel/apps/api/internal/config" + "github.com/zero-ppanel/zero-ppanel/pkg/cryptox" + "github.com/zero-ppanel/zero-ppanel/pkg/xerr" + "github.com/zeromicro/go-zero/rest/httpx" +) + +type DecryptMiddleware struct { + conf config.Config +} + +func NewDecryptMiddleware(c config.Config) *DecryptMiddleware { + return &DecryptMiddleware{conf: c} +} + +func (m *DecryptMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if !m.conf.Security.Enable { + next(w, r) + return + } + + if r.Header.Get("Login-Type") != "device" { + next(w, r) + return + } + + secret := m.conf.Security.SecuritySecret + rw := newEncryptResponseWriter(w, secret) + + // 解密 GET query + query := r.URL.Query() + dataStr := query.Get("data") + timeStr := query.Get("time") + if dataStr != "" && timeStr != "" { + if plain, err := cryptox.Decrypt(dataStr, secret, timeStr); err == nil { + params := map[string]interface{}{} + if json.Unmarshal(plain, ¶ms) == nil { + for k, v := range params { + query.Set(k, fmt.Sprintf("%v", v)) + } + query.Del("data") + query.Del("time") + rawQuery := query.Encode() + if strings.Contains(r.RequestURI, "?") { + r.RequestURI = r.RequestURI[:strings.Index(r.RequestURI, "?")] + "?" + rawQuery + } + r.URL.RawQuery = rawQuery + } + } + } + + // 解密 POST body + if r.Body != nil { + body, err := io.ReadAll(r.Body) + if err != nil || len(body) == 0 { + // body 为空或读取失败,直接放行 + r.Body = io.NopCloser(bytes.NewBuffer(body)) + next(rw, r) + rw.flush() + return + } + + var envelope struct { + Data string `json:"data"` + Time string `json:"time"` + } + if err := json.Unmarshal(body, &envelope); err != nil || envelope.Data == "" { + httpx.Error(w, xerr.NewErrCode(xerr.DecryptFailed)) + return + } + + plain, err := cryptox.Decrypt(envelope.Data, secret, envelope.Time) + if err != nil { + httpx.Error(w, xerr.NewErrCode(xerr.DecryptFailed)) + return + } + r.Body = io.NopCloser(bytes.NewBuffer(plain)) + } + + next(rw, r) + rw.flush() + } +} + +// encryptResponseWriter 拦截响应,加密 data 字段 +type encryptResponseWriter struct { + http.ResponseWriter + body *bytes.Buffer + secret string + status int +} + +func newEncryptResponseWriter(w http.ResponseWriter, secret string) *encryptResponseWriter { + return &encryptResponseWriter{ + ResponseWriter: w, + body: new(bytes.Buffer), + secret: secret, + status: http.StatusOK, + } +} + +func (rw *encryptResponseWriter) WriteHeader(code int) { + rw.status = code +} + +func (rw *encryptResponseWriter) Write(data []byte) (int, error) { + return rw.body.Write(data) +} + +func (rw *encryptResponseWriter) WriteString(s string) (int, error) { + return rw.body.WriteString(s) +} + +func (rw *encryptResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + return rw.ResponseWriter.(http.Hijacker).Hijack() +} + +func (rw *encryptResponseWriter) flush() { + buf := rw.body.Bytes() + out := buf + + // 尝试加密 data 字段 + params := map[string]interface{}{} + if err := json.Unmarshal(buf, ¶ms); err == nil { + if data := params["data"]; data != nil { + var jsonData []byte + if str, ok := data.(string); ok { + jsonData = []byte(str) + } else { + jsonData, _ = json.Marshal(data) + } + if dataB64, nonce, err := cryptox.Encrypt(jsonData, rw.secret); err == nil { + params["data"] = map[string]interface{}{ + "data": dataB64, + "time": nonce, + } + if enc, err := json.Marshal(params); err == nil { + out = enc + } + } + } + } + + rw.ResponseWriter.WriteHeader(rw.status) + rw.ResponseWriter.Write(out) +} diff --git a/apps/api/internal/middleware/signatureMiddleware.go b/apps/api/internal/middleware/signatureMiddleware.go new file mode 100644 index 0000000..54152bd --- /dev/null +++ b/apps/api/internal/middleware/signatureMiddleware.go @@ -0,0 +1,83 @@ +package middleware + +import ( + "bytes" + "io" + "net/http" + "strings" + + "github.com/zero-ppanel/zero-ppanel/apps/api/internal/config" + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zero-ppanel/zero-ppanel/pkg/xerr" + "github.com/zeromicro/go-zero/rest/httpx" +) + +type SignatureMiddleware struct { + conf config.Config + validator *signature.Validator +} + +func NewSignatureMiddleware(c config.Config, store signature.NonceStore) *SignatureMiddleware { + return &SignatureMiddleware{ + conf: c, + validator: signature.NewValidator(c.AppSignature, store), + } +} + +func (m *SignatureMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + appId := r.Header.Get("X-App-Id") + // X-App-Id 为空,提示非法访问 + if appId == "" { + httpx.Error(w, xerr.NewErrCode(xerr.InvalidAccess)) + return + } + + // SkipPrefixes 白名单 + for _, prefix := range m.conf.AppSignature.SkipPrefixes { + if strings.HasPrefix(r.URL.Path, prefix) { + next(w, r) + return + } + } + + timestamp := r.Header.Get("X-Timestamp") + nonce := r.Header.Get("X-Nonce") + sig := r.Header.Get("X-Signature") + + if timestamp == "" || nonce == "" || sig == "" { + httpx.Error(w, xerr.NewErrCode(xerr.SignatureMissing)) + return + } + + // 读取 body(签名对原始 body bytes 计算) + var bodyBytes []byte + if r.Body != nil { + bodyBytes, _ = io.ReadAll(r.Body) + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } + + sts := signature.BuildStringToSign(r.Method, r.URL.Path, r.URL.RawQuery, bodyBytes, appId, timestamp, nonce) + + if err := m.validator.Validate(r.Context(), appId, timestamp, nonce, sig, sts); err != nil { + code := mapSignatureErr(err) + httpx.Error(w, xerr.NewErrCode(code)) + return + } + + next(w, r) + } +} + +func mapSignatureErr(err error) int { + switch err { + case signature.ErrSignatureMissing: + return xerr.SignatureMissing + case signature.ErrSignatureExpired: + return xerr.SignatureExpired + case signature.ErrSignatureReplay: + return xerr.SignatureReplay + default: + return xerr.SignatureInvalid + } +} diff --git a/apps/api/internal/svc/serviceContext.go b/apps/api/internal/svc/serviceContext.go index 9ba211a..6c3ab52 100644 --- a/apps/api/internal/svc/serviceContext.go +++ b/apps/api/internal/svc/serviceContext.go @@ -5,18 +5,28 @@ package svc import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/config" - "github.com/zero-ppanel/zero-ppanel/apps/rpc/core/coreclient" + "github.com/zero-ppanel/zero-ppanel/apps/api/internal/middleware" + coreClient "github.com/zero-ppanel/zero-ppanel/apps/rpc/core/coreclient" + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/zrpc" ) type ServiceContext struct { - Config config.Config - CoreRpc coreClient.Core + Config config.Config + CoreRpc coreClient.Core + SignatureMiddleware *middleware.SignatureMiddleware + DecryptMiddleware *middleware.DecryptMiddleware } func NewServiceContext(c config.Config) *ServiceContext { + rds := redis.MustNewRedis(c.CacheRedis) + nonceStore := signature.NewRedisNonceStore(rds) + return &ServiceContext{ - Config: c, - CoreRpc: coreClient.NewCore(zrpc.MustNewClient(c.CoreRpc)), + Config: c, + CoreRpc: coreClient.NewCore(zrpc.MustNewClient(c.CoreRpc)), + SignatureMiddleware: middleware.NewSignatureMiddleware(c, nonceStore), + DecryptMiddleware: middleware.NewDecryptMiddleware(c), } } diff --git a/apps/api/internal/types/types.go b/apps/api/internal/types/types.go index 1c7175c..c4ecb05 100644 --- a/apps/api/internal/types/types.go +++ b/apps/api/internal/types/types.go @@ -10,11 +10,6 @@ type AnnouncementResp struct { CreatedAt string `json:"created_at"` } -type AuthResp struct { - Token string `json:"token"` - Expire int64 `json:"expire"` -} - type CloseOrderReq struct { OrderNo string `path:"order_no"` } @@ -63,6 +58,10 @@ type HealthResp struct { Status string `json:"status"` } +type LoginResp struct { + Token string `json:"token"` +} + type OrderDetailReq struct { OrderNo string `path:"order_no"` } @@ -84,9 +83,14 @@ type PaymentMethodResp struct { } type ResetPasswordReq struct { - Email string `json:"email"` - Password string `json:"password"` - Code string `json:"code"` + Identifier string `json:"identifier"` + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + Code string `json:"code,optional"` + IP string `header:"X-Original-Forwarded-For,optional"` + UserAgent string `header:"User-Agent,optional"` + LoginType string `header:"Login-Type,optional"` + CfToken string `json:"cf_token,optional"` } type SendEmailCodeReq struct { @@ -132,15 +136,25 @@ type UserInfoResp struct { } type UserLoginReq struct { - Email string `json:"email"` - Password string `json:"password"` + Identifier string `json:"identifier"` + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + IP string `header:"X-Original-Forwarded-For,optional"` + UserAgent string `header:"User-Agent,optional"` + LoginType string `header:"Login-Type,optional"` + CfToken string `json:"cf_token,optional"` } type UserRegisterReq struct { - Email string `json:"email"` - Password string `json:"password"` - Code string `json:"code"` - ReferCode string `json:"refer_code,optional"` + Identifier string `json:"identifier"` + Email string `json:"email" validate:"required"` + Password string `json:"password" validate:"required"` + Invite string `json:"invite,optional"` + Code string `json:"code,optional"` + IP string `header:"X-Original-Forwarded-For,optional"` + UserAgent string `header:"User-Agent,optional"` + LoginType string `header:"Login-Type,optional"` + CfToken string `json:"cf_token,optional"` } type UserSubscribeResp struct { diff --git a/apps/api/ppanel.go b/apps/api/ppanel.go index 90114f4..6592990 100644 --- a/apps/api/ppanel.go +++ b/apps/api/ppanel.go @@ -10,9 +10,11 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/api/internal/config" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/handler" "github.com/zero-ppanel/zero-ppanel/apps/api/internal/svc" + "github.com/zero-ppanel/zero-ppanel/pkg/result" "github.com/zeromicro/go-zero/core/conf" "github.com/zeromicro/go-zero/rest" + "github.com/zeromicro/go-zero/rest/httpx" ) var configFile = flag.String("f", "etc/api-dev.yaml", "the config file") @@ -27,8 +29,13 @@ func main() { defer server.Stop() ctx := svc.NewServiceContext(c) + server.Use(ctx.SignatureMiddleware.Handle) + server.Use(ctx.DecryptMiddleware.Handle) handler.RegisterHandlers(server, ctx) + // Registe global http error handler + httpx.SetErrorHandler(result.ErrHandler) + fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) server.Start() } diff --git a/apps/node/etc/node-dev.yaml b/apps/node/etc/node-dev.yaml index 06ac537..fc4e751 100644 --- a/apps/node/etc/node-dev.yaml +++ b/apps/node/etc/node-dev.yaml @@ -28,3 +28,17 @@ MySQL: Redis: Host: 127.0.0.1:6379 Type: node + +CacheRedis: + Host: 127.0.0.1:6379 + Type: node + +AppSignature: + AppSecrets: + android-client: "uB4G,XxL2{7b" + web-client: "uB4G,XxL2{7b" + ios-client: "uB4G,XxL2{7b" + mac-client: "uB4G,XxL2{7b" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/node/health diff --git a/apps/node/etc/node-prod.yaml b/apps/node/etc/node-prod.yaml index 354a6a8..d55f914 100644 --- a/apps/node/etc/node-prod.yaml +++ b/apps/node/etc/node-prod.yaml @@ -32,3 +32,18 @@ Redis: Host: "${REDIS_HOST}" Type: node Pass: "${REDIS_PASS}" + +CacheRedis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +AppSignature: + AppSecrets: + android-client: "${APP_SECRET}" + web-client: "${APP_SECRET}" + ios-client: "${APP_SECRET}" + mac-client: "${APP_SECRET}" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/node/health diff --git a/apps/node/etc/node-test.yaml b/apps/node/etc/node-test.yaml index 77ca8aa..bfa4bcf 100644 --- a/apps/node/etc/node-test.yaml +++ b/apps/node/etc/node-test.yaml @@ -30,3 +30,17 @@ MySQL: Redis: Host: redis:6379 Type: node + +CacheRedis: + Host: redis:6379 + Type: node + +AppSignature: + AppSecrets: + android-client: "uB4G,XxL2{7b" + web-client: "uB4G,XxL2{7b" + ios-client: "uB4G,XxL2{7b" + mac-client: "uB4G,XxL2{7b" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/node/health diff --git a/apps/node/internal/config/config.go b/apps/node/internal/config/config.go index 9b36470..9855e49 100644 --- a/apps/node/internal/config/config.go +++ b/apps/node/internal/config/config.go @@ -3,8 +3,15 @@ package config -import "github.com/zeromicro/go-zero/rest" +import ( + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zeromicro/go-zero/core/stores/redis" + "github.com/zeromicro/go-zero/rest" +) type Config struct { rest.RestConf + NodeSecret string + CacheRedis redis.RedisConf + AppSignature signature.SignatureConf } diff --git a/apps/node/internal/handler/common/healthHandler.go b/apps/node/internal/handler/common/healthHandler.go index 6349dfd..778f379 100644 --- a/apps/node/internal/handler/common/healthHandler.go +++ b/apps/node/internal/handler/common/healthHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/common" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func HealthHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := common.NewHealthLogic(r.Context(), svcCtx) resp, err := l.Health() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/node/internal/handler/node/getServerConfigHandler.go b/apps/node/internal/handler/node/getServerConfigHandler.go index ee6833d..32b4091 100644 --- a/apps/node/internal/handler/node/getServerConfigHandler.go +++ b/apps/node/internal/handler/node/getServerConfigHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetServerConfigHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := node.NewGetServerConfigLogic(r.Context(), svcCtx) resp, err := l.GetServerConfig() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/node/internal/handler/node/getServerUserListHandler.go b/apps/node/internal/handler/node/getServerUserListHandler.go index c6e657d..528a86c 100644 --- a/apps/node/internal/handler/node/getServerUserListHandler.go +++ b/apps/node/internal/handler/node/getServerUserListHandler.go @@ -8,17 +8,13 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func GetServerUserListHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { l := node.NewGetServerUserListLogic(r.Context(), svcCtx) resp, err := l.GetServerUserList() - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.OkJsonCtx(r.Context(), w, resp) - } + result.HttpResult(r, w, resp, err) } } diff --git a/apps/node/internal/handler/node/pushOnlineUsersHandler.go b/apps/node/internal/handler/node/pushOnlineUsersHandler.go index ebc7c2a..f7f0a8b 100644 --- a/apps/node/internal/handler/node/pushOnlineUsersHandler.go +++ b/apps/node/internal/handler/node/pushOnlineUsersHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func PushOnlineUsersHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.PushOnlineUsersReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := node.NewPushOnlineUsersLogic(r.Context(), svcCtx) err := l.PushOnlineUsers(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/node/internal/handler/node/pushStatusHandler.go b/apps/node/internal/handler/node/pushStatusHandler.go index 1c2745f..27fb97d 100644 --- a/apps/node/internal/handler/node/pushStatusHandler.go +++ b/apps/node/internal/handler/node/pushStatusHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func PushStatusHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.PushStatusReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := node.NewPushStatusLogic(r.Context(), svcCtx) err := l.PushStatus(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/node/internal/handler/node/pushUserTrafficHandler.go b/apps/node/internal/handler/node/pushUserTrafficHandler.go index 6985130..8fbc545 100644 --- a/apps/node/internal/handler/node/pushUserTrafficHandler.go +++ b/apps/node/internal/handler/node/pushUserTrafficHandler.go @@ -9,23 +9,19 @@ import ( "github.com/zero-ppanel/zero-ppanel/apps/node/internal/logic/node" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/svc" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/types" - "github.com/zeromicro/go-zero/rest/httpx" + "github.com/zero-ppanel/zero-ppanel/pkg/result" ) func PushUserTrafficHandler(svcCtx *svc.ServiceContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req types.PushUserTrafficReq - if err := httpx.Parse(r, &req); err != nil { - httpx.ErrorCtx(r.Context(), w, err) + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) return } l := node.NewPushUserTrafficLogic(r.Context(), svcCtx) err := l.PushUserTraffic(&req) - if err != nil { - httpx.ErrorCtx(r.Context(), w, err) - } else { - httpx.Ok(w) - } + result.HttpResult(r, w, nil, err) } } diff --git a/apps/node/internal/middleware/signatureMiddleware.go b/apps/node/internal/middleware/signatureMiddleware.go new file mode 100644 index 0000000..48fd3c1 --- /dev/null +++ b/apps/node/internal/middleware/signatureMiddleware.go @@ -0,0 +1,88 @@ +package middleware + +import ( + "bytes" + "io" + "net/http" + "strings" + + "github.com/zero-ppanel/zero-ppanel/apps/node/internal/config" + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zero-ppanel/zero-ppanel/pkg/xerr" + "github.com/zeromicro/go-zero/rest/httpx" +) + +type SignatureMiddleware struct { + conf config.Config + validator *signature.Validator +} + +func NewSignatureMiddleware(c config.Config, store signature.NonceStore) *SignatureMiddleware { + return &SignatureMiddleware{ + conf: c, + validator: signature.NewValidator(c.AppSignature, store), + } +} + +func (m *SignatureMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + appId := r.Header.Get("X-App-Id") + if appId == "" { + next(w, r) + return + } + + for _, prefix := range m.conf.AppSignature.SkipPrefixes { + if strings.HasPrefix(r.URL.Path, prefix) { + next(w, r) + return + } + } + + timestamp := r.Header.Get("X-Timestamp") + nonce := r.Header.Get("X-Nonce") + sig := r.Header.Get("X-Signature") + + if timestamp == "" || nonce == "" || sig == "" { + httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(xerr.SignatureMissing)) + return + } + + var bodyBytes []byte + if r.Body != nil { + bodyBytes, _ = io.ReadAll(r.Body) + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) + } + + sts := signature.BuildStringToSign(r.Method, r.URL.Path, r.URL.RawQuery, bodyBytes, appId, timestamp, nonce) + + if err := m.validator.Validate(r.Context(), appId, timestamp, nonce, sig, sts); err != nil { + code := mapSignatureErr(err) + httpx.WriteJson(w, http.StatusUnauthorized, buildErrResp(code)) + return + } + + next(w, r) + } +} + +func mapSignatureErr(err error) int { + switch err { + case signature.ErrSignatureMissing: + return xerr.SignatureMissing + case signature.ErrSignatureExpired: + return xerr.SignatureExpired + case signature.ErrSignatureReplay: + return xerr.SignatureReplay + default: + return xerr.SignatureInvalid + } +} + +func buildErrResp(code int) map[string]interface{} { + return map[string]interface{}{ + "code": code, + "msg": xerr.MapErrMsg(code), + "data": nil, + } +} diff --git a/apps/node/internal/svc/serviceContext.go b/apps/node/internal/svc/serviceContext.go index 9ab11e3..4647be2 100644 --- a/apps/node/internal/svc/serviceContext.go +++ b/apps/node/internal/svc/serviceContext.go @@ -6,17 +6,24 @@ package svc import ( "github.com/zero-ppanel/zero-ppanel/apps/node/internal/config" "github.com/zero-ppanel/zero-ppanel/apps/node/internal/middleware" + "github.com/zero-ppanel/zero-ppanel/pkg/signature" + "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/rest" ) type ServiceContext struct { - Config config.Config - NodeAuthMiddleware rest.Middleware + Config config.Config + NodeAuthMiddleware rest.Middleware + SignatureMiddleware *middleware.SignatureMiddleware } func NewServiceContext(c config.Config) *ServiceContext { + rds := redis.MustNewRedis(c.CacheRedis) + nonceStore := signature.NewRedisNonceStore(rds) + return &ServiceContext{ - Config: c, - NodeAuthMiddleware: middleware.NewNodeAuthMiddleware().Handle, + Config: c, + NodeAuthMiddleware: middleware.NewNodeAuthMiddleware().Handle, + SignatureMiddleware: middleware.NewSignatureMiddleware(c, nonceStore), } } diff --git a/apps/node/ppanelnode.go b/apps/node/ppanelnode.go index 1c5c48f..1b4b3a6 100644 --- a/apps/node/ppanelnode.go +++ b/apps/node/ppanelnode.go @@ -27,6 +27,7 @@ func main() { defer server.Stop() ctx := svc.NewServiceContext(c) + server.Use(ctx.SignatureMiddleware.Handle) handler.RegisterHandlers(server, ctx) fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) diff --git a/apps/rpc/core/core.proto b/apps/rpc/core/core.proto index de1b351..c3e3b72 100644 --- a/apps/rpc/core/core.proto +++ b/apps/rpc/core/core.proto @@ -18,6 +18,7 @@ message BasicResponse { // ---------------------------------------------------------------------------- message GetUserInfoReq { int64 id = 1; + string email = 2; // 用于根据邮箱查询用户 } message GetUserInfoResp { @@ -25,6 +26,9 @@ message GetUserInfoResp { string email = 2; string role = 3; string uuid = 4; + string password = 5; // 用于验证密码 + bool is_disabled = 6; // 用户是否被禁用 + bool is_deleted = 7; // 用户是否已被删除 } // ---------------------------------------------------------------------------- diff --git a/apps/rpc/core/core/core.pb.go b/apps/rpc/core/core/core.pb.go index 6af0c1d..3fc7c61 100644 --- a/apps/rpc/core/core/core.pb.go +++ b/apps/rpc/core/core/core.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.11 -// protoc v6.33.4 +// protoc-gen-go v1.36.10 +// protoc v4.25.2 // source: core.proto package core @@ -118,6 +118,7 @@ func (x *BasicResponse) GetMsg() string { type GetUserInfoReq struct { state protoimpl.MessageState `protogen:"open.v1"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` // 用于根据邮箱查询用户 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -159,12 +160,22 @@ func (x *GetUserInfoReq) GetId() int64 { return 0 } +func (x *GetUserInfoReq) GetEmail() string { + if x != nil { + return x.Email + } + return "" +} + type GetUserInfoResp struct { state protoimpl.MessageState `protogen:"open.v1"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` Role string `protobuf:"bytes,3,opt,name=role,proto3" json:"role,omitempty"` Uuid string `protobuf:"bytes,4,opt,name=uuid,proto3" json:"uuid,omitempty"` + Password string `protobuf:"bytes,5,opt,name=password,proto3" json:"password,omitempty"` // 用于验证密码 + IsDisabled bool `protobuf:"varint,6,opt,name=is_disabled,json=isDisabled,proto3" json:"is_disabled,omitempty"` // 用户是否被禁用 + IsDeleted bool `protobuf:"varint,7,opt,name=is_deleted,json=isDeleted,proto3" json:"is_deleted,omitempty"` // 用户是否已被删除 unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -227,6 +238,27 @@ func (x *GetUserInfoResp) GetUuid() string { return "" } +func (x *GetUserInfoResp) GetPassword() string { + if x != nil { + return x.Password + } + return "" +} + +func (x *GetUserInfoResp) GetIsDisabled() bool { + if x != nil { + return x.IsDisabled + } + return false +} + +func (x *GetUserInfoResp) GetIsDeleted() bool { + if x != nil { + return x.IsDeleted + } + return false +} + // ---------------------------------------------------------------------------- // Node 服务定义 // ---------------------------------------------------------------------------- @@ -351,14 +383,20 @@ const file_core_proto_rawDesc = "" + "\x05Empty\"5\n" + "\rBasicResponse\x12\x12\n" + "\x04code\x18\x01 \x01(\x05R\x04code\x12\x10\n" + - "\x03msg\x18\x02 \x01(\tR\x03msg\" \n" + + "\x03msg\x18\x02 \x01(\tR\x03msg\"6\n" + "\x0eGetUserInfoReq\x12\x0e\n" + - "\x02id\x18\x01 \x01(\x03R\x02id\"_\n" + + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x14\n" + + "\x05email\x18\x02 \x01(\tR\x05email\"\xbb\x01\n" + "\x0fGetUserInfoResp\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x14\n" + "\x05email\x18\x02 \x01(\tR\x05email\x12\x12\n" + "\x04role\x18\x03 \x01(\tR\x04role\x12\x12\n" + - "\x04uuid\x18\x04 \x01(\tR\x04uuid\" \n" + + "\x04uuid\x18\x04 \x01(\tR\x04uuid\x12\x1a\n" + + "\bpassword\x18\x05 \x01(\tR\bpassword\x12\x1f\n" + + "\vis_disabled\x18\x06 \x01(\bR\n" + + "isDisabled\x12\x1d\n" + + "\n" + + "is_deleted\x18\a \x01(\bR\tisDeleted\" \n" + "\x0eGetNodeInfoReq\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\"e\n" + "\x0fGetNodeInfoResp\x12\x0e\n" + diff --git a/apps/rpc/core/core/core_grpc.pb.go b/apps/rpc/core/core/core_grpc.pb.go index 2afd10f..967db4c 100644 --- a/apps/rpc/core/core/core_grpc.pb.go +++ b/apps/rpc/core/core/core_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.6.1 -// - protoc v6.33.4 +// - protoc-gen-go-grpc v1.5.1 +// - protoc v4.25.2 // source: core.proto package core @@ -103,13 +103,13 @@ type CoreServer interface { type UnimplementedCoreServer struct{} func (UnimplementedCoreServer) Ping(context.Context, *Empty) (*BasicResponse, error) { - return nil, status.Error(codes.Unimplemented, "method Ping not implemented") + return nil, status.Errorf(codes.Unimplemented, "method Ping not implemented") } func (UnimplementedCoreServer) GetUserInfo(context.Context, *GetUserInfoReq) (*GetUserInfoResp, error) { - return nil, status.Error(codes.Unimplemented, "method GetUserInfo not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GetUserInfo not implemented") } func (UnimplementedCoreServer) GetNodeInfo(context.Context, *GetNodeInfoReq) (*GetNodeInfoResp, error) { - return nil, status.Error(codes.Unimplemented, "method GetNodeInfo not implemented") + return nil, status.Errorf(codes.Unimplemented, "method GetNodeInfo not implemented") } func (UnimplementedCoreServer) mustEmbedUnimplementedCoreServer() {} func (UnimplementedCoreServer) testEmbeddedByValue() {} @@ -122,7 +122,7 @@ type UnsafeCoreServer interface { } func RegisterCoreServer(s grpc.ServiceRegistrar, srv CoreServer) { - // If the following call panics, it indicates UnimplementedCoreServer was + // If the following call pancis, it indicates UnimplementedCoreServer was // embedded by pointer and is nil. This will cause panics if an // unimplemented method is ever invoked, so we test this at initialization // time to prevent it from happening at runtime later due to I/O. diff --git a/apps/rpc/core/coreClient/core.go b/apps/rpc/core/coreClient/core.go index 46d1bbd..bbb86f8 100644 --- a/apps/rpc/core/coreClient/core.go +++ b/apps/rpc/core/coreClient/core.go @@ -2,7 +2,7 @@ // goctl 1.9.2 // Source: core.proto -package coreClient +package coreclient import ( "context" diff --git a/apps/rpc/core/etc/core.yaml b/apps/rpc/core/etc/core.yaml new file mode 100644 index 0000000..97467fc --- /dev/null +++ b/apps/rpc/core/etc/core.yaml @@ -0,0 +1,6 @@ +Name: core.rpc +ListenOn: 0.0.0.0:8080 +Etcd: + Hosts: + - 127.0.0.1:2379 + Key: core.rpc diff --git a/apps/rpc/core/internal/logic/getUserInfoLogic.go b/apps/rpc/core/internal/logic/getUserInfoLogic.go index 8a25f73..1870126 100644 --- a/apps/rpc/core/internal/logic/getUserInfoLogic.go +++ b/apps/rpc/core/internal/logic/getUserInfoLogic.go @@ -2,6 +2,7 @@ package logic import ( "context" + "errors" "github.com/zero-ppanel/zero-ppanel/apps/rpc/core/core" "github.com/zero-ppanel/zero-ppanel/apps/rpc/core/internal/svc" @@ -25,7 +26,48 @@ func NewGetUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUs // 用户相关 func (l *GetUserInfoLogic) GetUserInfo(in *core.GetUserInfoReq) (*core.GetUserInfoResp, error) { - // todo: add your logic here and delete this line + // 暂不支持空参数查询 + if in.Email == "" && in.Id == 0 { + return nil, errors.New("id or email is required") + } - return &core.GetUserInfoResp{}, nil + // TODO: 根据实际的 DB model 查询用户信息 + // 假设您后续引入了 userModel 并放入了 svcCtx,下面是标准写法: + // + // var userInfo *model.User + // var err error + // if in.Email != "" { + // userInfo, err = l.svcCtx.UserModel.FindOneByEmail(l.ctx, in.Email) + // } else { + // userInfo, err = l.svcCtx.UserModel.FindOne(l.ctx, in.Id) + // } + // + // if err != nil { + // if errors.Is(err, sqlc.ErrNotFound) { + // return &core.GetUserInfoResp{}, nil // 用户不存在,由业务层通过 Resp 的零值判断 + // } + // return nil, err + // } + + // =============== Mock 数据用于联调测试 =============== + // 为了使您的 API 服务现在的登录重构直接能进行 Postman 联调, + // 此处返回一个模拟存在的用户(您可以直接用这个邮箱及秘密进行登录尝试)。 + // Mock Email: admin@admin.com + // Mock Password: admin (对应的 bcrypted hash) + if in.Email == "admin@admin.com" || in.Id == 1 { + return &core.GetUserInfoResp{ + Id: 1, + Email: "admin@admin.com", + Role: "admin", // 模拟管理员 + Password: "$2a$10$X8H.V2hG1E8c3rT5fH8h3.3nK290X8t9gY1N4/n.9s3.m4G0W.3yW", // `admin` 加密后的结果 + Uuid: "mock-uuid-123", + IsDisabled: false, + IsDeleted: false, + }, nil + } + + // 模拟未找到用户 + return &core.GetUserInfoResp{ + Id: 0, // Id=0 表示没找到 + }, nil } diff --git a/go.mod b/go.mod index 3c06e77..6324ce1 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,13 @@ module github.com/zero-ppanel/zero-ppanel -go 1.23 +go 1.24.0 require ( github.com/golang-jwt/jwt/v5 v5.2.1 github.com/hibiken/asynq v0.25.1 + github.com/pkg/errors v0.9.1 github.com/zeromicro/go-zero v1.7.6 + golang.org/x/crypto v0.48.0 google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.36.1 ) @@ -71,11 +73,11 @@ require ( go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 // indirect - golang.org/x/net v0.33.0 // indirect + golang.org/x/net v0.49.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.28.0 // indirect - golang.org/x/term v0.27.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/term v0.40.0 // indirect + golang.org/x/text v0.34.0 // indirect golang.org/x/time v0.8.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect diff --git a/go.sum b/go.sum index 4029aac..a9bf443 100644 --- a/go.sum +++ b/go.sum @@ -200,6 +200,8 @@ go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -208,8 +210,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -224,15 +226,15 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= +golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -240,8 +242,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc= +golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg= 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= diff --git a/goctl_tpl/api/config.tpl b/goctl_tpl/api/config.tpl new file mode 100644 index 0000000..5fa7ad6 --- /dev/null +++ b/goctl_tpl/api/config.tpl @@ -0,0 +1,12 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package config + +import {{.authImport}} + +type Config struct { + rest.RestConf + {{.auth}} + {{.jwtTrans}} +} diff --git a/goctl_tpl/api/context.tpl b/goctl_tpl/api/context.tpl new file mode 100644 index 0000000..c85dfb0 --- /dev/null +++ b/goctl_tpl/api/context.tpl @@ -0,0 +1,20 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package svc + +import ( + {{.configImport}} +) + +type ServiceContext struct { + Config {{.config}} + {{.middleware}} +} + +func NewServiceContext(c {{.config}}) *ServiceContext { + return &ServiceContext{ + Config: c, + {{.middlewareAssignment}} + } +} diff --git a/goctl_tpl/api/etc.tpl b/goctl_tpl/api/etc.tpl new file mode 100644 index 0000000..ed55cf1 --- /dev/null +++ b/goctl_tpl/api/etc.tpl @@ -0,0 +1,3 @@ +Name: {{.serviceName}} +Host: {{.host}} +Port: {{.port}} diff --git a/goctl_tpl/api/handler.tpl b/goctl_tpl/api/handler.tpl new file mode 100644 index 0000000..40d101c --- /dev/null +++ b/goctl_tpl/api/handler.tpl @@ -0,0 +1,26 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package {{.PkgName}} + +import ( + "net/http" + + "github.com/zero-ppanel/zero-ppanel/pkg/result" + {{.ImportPackages}} +) + +{{if .HasDoc}}{{.Doc}}{{end}} +func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + {{if .HasRequest}}var req types.{{.RequestType}} + if err := result.Parse(r, &req); err != nil { + result.HttpResult(r, w, nil, err) + return + } + + {{end}}l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx) + {{if .HasResp}}resp, {{end}}err := l.{{.Call}}({{if .HasRequest}}&req{{end}}) + {{if .HasResp}}result.HttpResult(r, w, resp, err){{else}}result.HttpResult(r, w, nil, err){{end}} + } +} diff --git a/goctl_tpl/api/handler_test.tpl b/goctl_tpl/api/handler_test.tpl new file mode 100644 index 0000000..d1976ea --- /dev/null +++ b/goctl_tpl/api/handler_test.tpl @@ -0,0 +1,84 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package {{.PkgName}} + +import ( + "bytes" + {{if .HasRequest}}"encoding/json"{{end}} + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + {{.ImportPackages}} +) + +{{if .HasDoc}}{{.Doc}}{{end}} +func Test{{.HandlerName}}(t *testing.T) { + // new service context + c := config.Config{} + svcCtx := svc.NewServiceContext(c) + // init mock service context here + + tests := []struct { + name string + reqBody interface{} + wantStatus int + wantResp string + setupMocks func() + }{ + { + name: "invalid request body", + reqBody: "invalid", + wantStatus: http.StatusBadRequest, + wantResp: "unsupported type", // Adjust based on actual error response + setupMocks: func() { + // No setup needed for this test case + }, + }, + { + name: "handler error", + {{if .HasRequest}}reqBody: types.{{.RequestType}}{ + //TODO: add fields here + }, + {{end}}wantStatus: http.StatusBadRequest, + wantResp: "error", // Adjust based on actual error response + setupMocks: func() { + // Mock login logic to return an error + }, + }, + { + name: "handler successful", + {{if .HasRequest}}reqBody: types.{{.RequestType}}{ + //TODO: add fields here + }, + {{end}}wantStatus: http.StatusOK, + wantResp: `{"code":0,"msg":"success","data":{}}`, // Adjust based on actual success response + setupMocks: func() { + // Mock login logic to return success + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks() + var reqBody []byte + {{if .HasRequest}}var err error + reqBody, err = json.Marshal(tt.reqBody) + require.NoError(t, err){{end}} + req, err := http.NewRequest("POST", "/ut", bytes.NewBuffer(reqBody)) + require.NoError(t, err) + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + handler := {{.HandlerName}}(svcCtx) + handler.ServeHTTP(rr, req) + t.Log(rr.Body.String()) + assert.Equal(t, tt.wantStatus, rr.Code) + assert.Contains(t, rr.Body.String(), tt.wantResp) + }) + } +} diff --git a/goctl_tpl/api/integration_test.tpl b/goctl_tpl/api/integration_test.tpl new file mode 100644 index 0000000..e64c2f3 --- /dev/null +++ b/goctl_tpl/api/integration_test.tpl @@ -0,0 +1,120 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package main + +import ( + "net/http" + "net/http/httptest" + "testing" + "time" + + "{{.projectPkg}}/internal/config" + "{{.projectPkg}}/internal/handler" + "{{.projectPkg}}/internal/svc" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zeromicro/go-zero/rest" +) + +func TestMain(m *testing.M) { + // TODO: Add setup/teardown logic here if needed + m.Run() +} + +func TestServerIntegration(t *testing.T) { + // Create test server + c := config.Config{ + RestConf: rest.RestConf{ + Host: "127.0.0.1", + Port: 0, // Use random available port + }, + } + + server := rest.MustNewServer(c.RestConf) + defer server.Stop() + + ctx := svc.NewServiceContext(c) + handler.RegisterHandlers(server, ctx) + + // Start server in background + go func() { + server.Start() + }() + + // Wait for server to start + time.Sleep(100 * time.Millisecond) + + tests := []struct { + name string + method string + path string + body string + expectedStatus int + setup func() + }{ + { + name: "health check", + method: "GET", + path: "/health", + expectedStatus: http.StatusNotFound, // Adjust based on actual routes + setup: func() {}, + }, + {{if .hasRoutes}}{{range .routes}}{ + name: "{{.Method}} {{.Path}}", + method: "{{.Method}}", + path: "{{.Path}}", + expectedStatus: http.StatusOK, // TODO: Adjust expected status + setup: func() { + // TODO: Add setup logic for this endpoint + }, + }, + {{end}}{{end}}{ + name: "not found route", + method: "GET", + path: "/nonexistent", + expectedStatus: http.StatusNotFound, + setup: func() {}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setup() + + req, err := http.NewRequest(tt.method, tt.path, nil) + require.NoError(t, err) + + rr := httptest.NewRecorder() + server.ServeHTTP(rr, req) + + assert.Equal(t, tt.expectedStatus, rr.Code) + + // TODO: Add response body assertions + t.Logf("Response: %s", rr.Body.String()) + }) + } +} + +func TestServerLifecycle(t *testing.T) { + c := config.Config{ + RestConf: rest.RestConf{ + Host: "127.0.0.1", + Port: 0, + }, + } + + server := rest.MustNewServer(c.RestConf) + + // Test server can start and stop without errors + ctx := svc.NewServiceContext(c) + handler.RegisterHandlers(server, ctx) + + // In a real integration test, you might start the server in a goroutine + // and test actual HTTP requests, but for scaffolding we keep it simple + server.Stop() + + // TODO: Add more lifecycle tests as needed + assert.True(t, true, "Server lifecycle test passed") +} diff --git a/goctl_tpl/api/logic.tpl b/goctl_tpl/api/logic.tpl new file mode 100644 index 0000000..d89dc15 --- /dev/null +++ b/goctl_tpl/api/logic.tpl @@ -0,0 +1,29 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package {{.pkgName}} + +import ( + {{.imports}} +) + +type {{.logic}} struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +{{if .hasDoc}}{{.doc}}{{end}} +func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext) *{{.logic}} { + return &{{.logic}}{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} { + // todo: add your logic here and delete this line + + {{.returnString}} +} diff --git a/goctl_tpl/api/logic_test.tpl b/goctl_tpl/api/logic_test.tpl new file mode 100644 index 0000000..9a211df --- /dev/null +++ b/goctl_tpl/api/logic_test.tpl @@ -0,0 +1,72 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package {{.pkgName}} + +import ( + "context" + "testing" + + {{.imports}} + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test{{.logic}}_{{.function}}(t *testing.T) { + c := config.Config{} + mockSvcCtx := svc.NewServiceContext(c) + // init mock service context here + + tests := []struct { + name string + ctx context.Context + setupMocks func() + {{if .hasRequest}}req *{{.requestType}}{{end}} + wantErr bool + checkResp func{{if .hasResponse}}{{.responseType}}{{else}}(err error){{end}} + }{ + { + name: "response error", + ctx: context.Background(), + setupMocks: func() { + // mock data for this test case + }, + {{if .hasRequest}}req: &{{.requestType}}{ + // TODO: init your request here + },{{end}} + wantErr: true, + checkResp: func{{if .hasResponse}}{{.responseType}}{{else}}(err error){{end}} { + // TODO: Add your check logic here + }, + }, + { + name: "successful", + ctx: context.Background(), + setupMocks: func() { + // Mock data for this test case + }, + {{if .hasRequest}}req: &{{.requestType}}{ + // TODO: init your request here + },{{end}} + wantErr: false, + checkResp: func{{if .hasResponse}}{{.responseType}}{{else}}(err error){{end}} { + // TODO: Add your check logic here + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + tt.setupMocks() + l := New{{.logic}}(tt.ctx, mockSvcCtx) + {{if .hasResponse}}resp, {{end}}err := l.{{.function}}({{if .hasRequest}}tt.req{{end}}) + if tt.wantErr { + assert.Error(t, err) + } else { + require.NoError(t, err) + {{if .hasResponse}}assert.NotNil(t, resp){{end}} + } + tt.checkResp({{if .hasResponse}}resp, {{end}}err) + }) + } +} diff --git a/goctl_tpl/api/main.tpl b/goctl_tpl/api/main.tpl new file mode 100644 index 0000000..88c6fd9 --- /dev/null +++ b/goctl_tpl/api/main.tpl @@ -0,0 +1,29 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package main + +import ( + "flag" + "fmt" + + {{.importPackages}} +) + +var configFile = flag.String("f", "etc/{{.serviceName}}.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + + server := rest.MustNewServer(c.RestConf) + defer server.Stop() + + ctx := svc.NewServiceContext(c) + handler.RegisterHandlers(server, ctx) + + fmt.Printf("Starting server at %s:%d...\n", c.Host, c.Port) + server.Start() +} diff --git a/goctl_tpl/api/middleware.tpl b/goctl_tpl/api/middleware.tpl new file mode 100644 index 0000000..260e98d --- /dev/null +++ b/goctl_tpl/api/middleware.tpl @@ -0,0 +1,22 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package middleware + +import "net/http" + +type {{.name}} struct { +} + +func New{{.name}}() *{{.name}} { + return &{{.name}}{} +} + +func (m *{{.name}})Handle(next http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + // TODO generate middleware implement function, delete after code implementation + + // Passthrough to next handler if need + next(w, r) + } +} diff --git a/goctl_tpl/api/route-addition.tpl b/goctl_tpl/api/route-addition.tpl new file mode 100644 index 0000000..5a1b41f --- /dev/null +++ b/goctl_tpl/api/route-addition.tpl @@ -0,0 +1,4 @@ + + server.AddRoutes( + {{.routes}} {{.jwt}}{{.signature}} {{.prefix}} {{.timeout}} {{.maxBytes}} {{.sse}} + ) diff --git a/goctl_tpl/api/routes.tpl b/goctl_tpl/api/routes.tpl new file mode 100644 index 0000000..f972853 --- /dev/null +++ b/goctl_tpl/api/routes.tpl @@ -0,0 +1,15 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl {{.version}} + +package handler + +import ( + "net/http"{{if .hasTimeout}} + "time"{{end}} + + {{.importPackages}} +) + +func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) { + {{.routesAdditions}} +} diff --git a/goctl_tpl/api/sse_handler.tpl b/goctl_tpl/api/sse_handler.tpl new file mode 100644 index 0000000..84aea28 --- /dev/null +++ b/goctl_tpl/api/sse_handler.tpl @@ -0,0 +1,68 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package {{.PkgName}} + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/zeromicro/go-zero/core/logc" + "github.com/zeromicro/go-zero/core/threading" + {{if .HasRequest}}"github.com/zeromicro/go-zero/rest/httpx"{{end}} + {{.ImportPackages}} +) + +{{if .HasDoc}}{{.Doc}}{{end}} +func {{.HandlerName}}(svcCtx *svc.ServiceContext) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + {{if .HasRequest}}var req types.{{.RequestType}} + if err := httpx.Parse(r, &req); err != nil { + httpx.ErrorCtx(r.Context(), w, err) + return + } + + {{end}}// Buffer size of 16 is chosen as a reasonable default to balance throughput and memory usage. + // You can change this based on your application's needs. + // if your go-zero version less than 1.8.1, you need to add 3 lines below. + // w.Header().Set("Content-Type", "text/event-stream") + // w.Header().Set("Cache-Control", "no-cache") + // w.Header().Set("Connection", "keep-alive") + client := make(chan {{.ResponseType}}, 16) + + l := {{.LogicName}}.New{{.LogicType}}(r.Context(), svcCtx) + threading.GoSafeCtx(r.Context(), func() { + defer close(client) + err := l.{{.Call}}({{if .HasRequest}}&req, {{end}}client) + if err != nil { + logc.Errorw(r.Context(), "{{.HandlerName}}", logc.Field("error", err)) + return + } + }) + + for { + select { + case data, ok := <-client: + if !ok { + return + } + output, err := json.Marshal(data) + if err != nil { + logc.Errorw(r.Context(), "{{.HandlerName}}", logc.Field("error", err)) + continue + } + + if _, err := fmt.Fprintf(w, "data: %s\n\n", string(output)); err != nil { + logc.Errorw(r.Context(), "{{.HandlerName}}", logc.Field("error", err)) + return + } + if flusher, ok := w.(http.Flusher); ok { + flusher.Flush() + } + case <-r.Context().Done(): + return + } + } + } +} diff --git a/goctl_tpl/api/sse_logic.tpl b/goctl_tpl/api/sse_logic.tpl new file mode 100644 index 0000000..676cdf3 --- /dev/null +++ b/goctl_tpl/api/sse_logic.tpl @@ -0,0 +1,29 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package {{.pkgName}} + +import ( + {{.imports}} +) + +type {{.logic}} struct { + logx.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +{{if .hasDoc}}{{.doc}}{{end}} +func New{{.logic}}(ctx context.Context, svcCtx *svc.ServiceContext) *{{.logic}} { + return &{{.logic}}{ + Logger: logx.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *{{.logic}}) {{.function}}({{.request}}) {{.responseType}} { + // todo: add your logic here and delete this line + + {{.returnString}} +} diff --git a/goctl_tpl/api/svc_test.tpl b/goctl_tpl/api/svc_test.tpl new file mode 100644 index 0000000..10009d9 --- /dev/null +++ b/goctl_tpl/api/svc_test.tpl @@ -0,0 +1,60 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl {{.version}} + +package svc + +import ( + "testing" + + "{{.projectPkg}}/internal/config" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestNewServiceContext(t *testing.T) { + tests := []struct { + name string + config config.Config + setup func() config.Config + }{ + { + name: "default config", + setup: func() config.Config { + return config.Config{} + }, + }, + { + name: "valid config", + setup: func() config.Config { + return config.Config{ + // TODO: Add valid config values here + } + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := tt.setup() + svcCtx := NewServiceContext(c) + + // Basic assertions + require.NotNil(t, svcCtx) + assert.Equal(t, c, svcCtx.Config) + + // TODO: Add additional assertions for middleware and dependencies + }) + } +} + +func TestServiceContext_Initialization(t *testing.T) { + c := config.Config{} + svcCtx := NewServiceContext(c) + + // Verify service context is properly initialized + assert.NotNil(t, svcCtx) + assert.Equal(t, c, svcCtx.Config) + + // TODO: Add tests for middleware initialization if any + // TODO: Add tests for external dependencies if any +} diff --git a/goctl_tpl/api/template.tpl b/goctl_tpl/api/template.tpl new file mode 100644 index 0000000..2176441 --- /dev/null +++ b/goctl_tpl/api/template.tpl @@ -0,0 +1,24 @@ +syntax = "v1" + +info ( + title: // TODO: add title + desc: // TODO: add description + author: "{{.gitUser}}" + email: "{{.gitEmail}}" +) + +type request { + // TODO: add members here and delete this comment +} + +type response { + // TODO: add members here and delete this comment +} + +service {{.serviceName}} { + @handler GetUser // TODO: set handler name and delete this comment + get /users/id/:userId(request) returns(response) + + @handler CreateUser // TODO: set handler name and delete this comment + post /users/create(request) +} diff --git a/goctl_tpl/api/types.tpl b/goctl_tpl/api/types.tpl new file mode 100644 index 0000000..8015c57 --- /dev/null +++ b/goctl_tpl/api/types.tpl @@ -0,0 +1,8 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl {{.version}} + +package types{{if .containsTime}} +import ( + "time" +){{end}} +{{.types}} diff --git a/goctl_tpl/docker/docker.tpl b/goctl_tpl/docker/docker.tpl new file mode 100644 index 0000000..468f724 --- /dev/null +++ b/goctl_tpl/docker/docker.tpl @@ -0,0 +1,36 @@ +FROM golang:{{.Version}}alpine AS builder + +LABEL stage=gobuilder + +ENV CGO_ENABLED 0 + +{{if .HasTimezone}} +RUN apk update --no-cache && apk add --no-cache tzdata +{{- end}} + +WORKDIR /build + +ADD go.mod . +ADD go.sum . +RUN go mod download +COPY . . + +RUN go build -ldflags="-s -w" -o /app/{{.ExeFile}} {{.GoMainFrom}} + + +FROM {{.BaseImage}} + +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt +{{if .HasTimezone -}} +COPY --from=builder /usr/share/zoneinfo/{{.Timezone}} /usr/share/zoneinfo/{{.Timezone}} +ENV TZ {{.Timezone}} +{{end}} +WORKDIR /app +COPY --from=builder /app/{{.ExeFile}} /app/{{.ExeFile}} +{{if .Argument -}} +COPY {{.GoRelPath}}/etc /app/etc +{{- end}} +{{if .HasPort}} +EXPOSE {{.Port}} +{{end}} +CMD ["./{{.ExeFile}}"{{.Argument}}] diff --git a/goctl_tpl/gateway/etc.tpl b/goctl_tpl/gateway/etc.tpl new file mode 100644 index 0000000..0a70f1a --- /dev/null +++ b/goctl_tpl/gateway/etc.tpl @@ -0,0 +1,18 @@ +Name: gateway-example # gateway name +Host: localhost # gateway host +Port: 8888 # gateway port +Upstreams: # upstreams + - Grpc: # grpc upstream + Target: 0.0.0.0:8080 # grpc target,the direct grpc server address,for only one node +# Endpoints: [0.0.0.0:8080,192.168.120.1:8080] # grpc endpoints, the grpc server address list, for multiple nodes +# Etcd: # etcd config, if you want to use etcd to discover the grpc server address +# Hosts: [127.0.0.1:2378,127.0.0.1:2379] # etcd hosts +# Key: greet.grpc # the discovery key + # protoset mode + ProtoSets: + - hello.pb + # Mappings can also be written in proto options +# Mappings: # routes mapping +# - Method: get +# Path: /ping +# RpcPath: hello.Hello/Ping diff --git a/goctl_tpl/gateway/main.tpl b/goctl_tpl/gateway/main.tpl new file mode 100644 index 0000000..6273451 --- /dev/null +++ b/goctl_tpl/gateway/main.tpl @@ -0,0 +1,20 @@ +package main + +import ( + "flag" + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/gateway" +) + +var configFile = flag.String("f", "etc/gateway.yaml", "config file") + +func main() { + flag.Parse() + + var c gateway.GatewayConf + conf.MustLoad(*configFile, &c) + gw := gateway.MustNewServer(c) + defer gw.Stop() + gw.Start() +} diff --git a/goctl_tpl/kube/deployment.tpl b/goctl_tpl/kube/deployment.tpl new file mode 100644 index 0000000..1d7fbc5 --- /dev/null +++ b/goctl_tpl/kube/deployment.tpl @@ -0,0 +1,117 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{.Name}} + namespace: {{.Namespace}} + labels: + app: {{.Name}} +spec: + replicas: {{.Replicas}} + revisionHistoryLimit: {{.Revisions}} + selector: + matchLabels: + app: {{.Name}} + template: + metadata: + labels: + app: {{.Name}} + spec:{{if .ServiceAccount}} + serviceAccountName: {{.ServiceAccount}}{{end}} + containers: + - name: {{.Name}} + image: {{.Image}} + {{if .ImagePullPolicy}}imagePullPolicy: {{.ImagePullPolicy}} + {{end}}ports: + - containerPort: {{.Port}} + readinessProbe: + tcpSocket: + port: {{.Port}} + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + tcpSocket: + port: {{.Port}} + initialDelaySeconds: 15 + periodSeconds: 20 + resources: + requests: + cpu: {{.RequestCpu}}m + memory: {{.RequestMem}}Mi + limits: + cpu: {{.LimitCpu}}m + memory: {{.LimitMem}}Mi + volumeMounts: + - name: timezone + mountPath: /etc/localtime + {{if .Secret}}imagePullSecrets: + - name: {{.Secret}} + {{end}}volumes: + - name: timezone + hostPath: + path: /usr/share/zoneinfo/Asia/Shanghai + +--- + +apiVersion: v1 +kind: Service +metadata: + name: {{.Name}}-svc + namespace: {{.Namespace}} +spec: + ports: + {{if .UseNodePort}}- nodePort: {{.NodePort}} + port: {{.Port}} + protocol: TCP + targetPort: {{.TargetPort}} + type: NodePort{{else}}- port: {{.Port}} + targetPort: {{.TargetPort}}{{end}} + selector: + app: {{.Name}} + +--- + +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{.Name}}-hpa-c + namespace: {{.Namespace}} + labels: + app: {{.Name}}-hpa-c +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{.Name}} + minReplicas: {{.MinReplicas}} + maxReplicas: {{.MaxReplicas}} + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 80 + +--- + +apiVersion: autoscaling/v2beta2 +kind: HorizontalPodAutoscaler +metadata: + name: {{.Name}}-hpa-m + namespace: {{.Namespace}} + labels: + app: {{.Name}}-hpa-m +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{.Name}} + minReplicas: {{.MinReplicas}} + maxReplicas: {{.MaxReplicas}} + metrics: + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 80 diff --git a/goctl_tpl/kube/job.tpl b/goctl_tpl/kube/job.tpl new file mode 100644 index 0000000..0da72ed --- /dev/null +++ b/goctl_tpl/kube/job.tpl @@ -0,0 +1,37 @@ +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{.Name}} + namespace: {{.Namespace}} +spec: + successfulJobsHistoryLimit: {{.SuccessfulJobsHistoryLimit}} + schedule: "{{.Schedule}}" + jobTemplate: + spec: + template: + spec:{{if .ServiceAccount}} + serviceAccountName: {{.ServiceAccount}}{{end}} + {{end}}containers: + - name: {{.Name}} + image: # todo image url + resources: + requests: + cpu: {{.RequestCpu}}m + memory: {{.RequestMem}}Mi + limits: + cpu: {{.LimitCpu}}m + memory: {{.LimitMem}}Mi + command: + - ./{{.ServiceName}} + - -f + - ./{{.Name}}.yaml + volumeMounts: + - name: timezone + mountPath: /etc/localtime + imagePullSecrets: + - name: # registry secret, if no, remove this + restartPolicy: OnFailure + volumes: + - name: timezone + hostPath: + path: /usr/share/zoneinfo/Asia/Shanghai diff --git a/goctl_tpl/model/customized.tpl b/goctl_tpl/model/customized.tpl new file mode 100644 index 0000000..e69de29 diff --git a/goctl_tpl/model/delete.tpl b/goctl_tpl/model/delete.tpl new file mode 100644 index 0000000..fb995c2 --- /dev/null +++ b/goctl_tpl/model/delete.tpl @@ -0,0 +1,14 @@ +func (m *default{{.upperStartCamelObject}}Model) Delete(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) error { + {{if .withCache}}{{if .containsIndexCache}}data, err:=m.FindOne(ctx, {{.lowerStartCamelPrimaryKey}}) + if err!=nil{ + return err + } + +{{end}} {{.keys}} + _, err {{if .containsIndexCache}}={{else}}:={{end}} m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("delete from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table) + return conn.ExecCtx(ctx, query, {{.lowerStartCamelPrimaryKey}}) + }, {{.keyValues}}){{else}}query := fmt.Sprintf("delete from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table) + _,err:=m.conn.ExecCtx(ctx, query, {{.lowerStartCamelPrimaryKey}}){{end}} + return err +} diff --git a/goctl_tpl/model/err.tpl b/goctl_tpl/model/err.tpl new file mode 100644 index 0000000..dc5eac4 --- /dev/null +++ b/goctl_tpl/model/err.tpl @@ -0,0 +1,5 @@ +package {{.pkg}} + +import "github.com/zeromicro/go-zero/core/stores/sqlx" + +var ErrNotFound = sqlx.ErrNotFound diff --git a/goctl_tpl/model/field.tpl b/goctl_tpl/model/field.tpl new file mode 100644 index 0000000..6b4ed38 --- /dev/null +++ b/goctl_tpl/model/field.tpl @@ -0,0 +1 @@ +{{.name}} {{.type}} {{.tag}} {{if .hasComment}}// {{.comment}}{{end}} \ No newline at end of file diff --git a/goctl_tpl/model/find-one-by-field-extra-method.tpl b/goctl_tpl/model/find-one-by-field-extra-method.tpl new file mode 100644 index 0000000..7e1df69 --- /dev/null +++ b/goctl_tpl/model/find-one-by-field-extra-method.tpl @@ -0,0 +1,8 @@ +func (m *default{{.upperStartCamelObject}}Model) formatPrimary(primary any) string { + return fmt.Sprintf("%s%v", {{.primaryKeyLeft}}, primary) +} + +func (m *default{{.upperStartCamelObject}}Model) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary any) error { + query := fmt.Sprintf("select %s from %s where {{.originalPrimaryField}} = {{if .postgreSql}}$1{{else}}?{{end}} limit 1", {{.lowerStartCamelObject}}Rows, m.table ) + return conn.QueryRowCtx(ctx, v, query, primary) +} diff --git a/goctl_tpl/model/find-one-by-field.tpl b/goctl_tpl/model/find-one-by-field.tpl new file mode 100644 index 0000000..dfcf923 --- /dev/null +++ b/goctl_tpl/model/find-one-by-field.tpl @@ -0,0 +1,30 @@ +func (m *default{{.upperStartCamelObject}}Model) FindOneBy{{.upperField}}(ctx context.Context, {{.in}}) (*{{.upperStartCamelObject}}, error) { + {{if .withCache}}{{.cacheKey}} + var resp {{.upperStartCamelObject}} + err := m.QueryRowIndexCtx(ctx, &resp, {{.cacheKeyVariable}}, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) { + query := fmt.Sprintf("select %s from %s where {{.originalField}} limit 1", {{.lowerStartCamelObject}}Rows, m.table) + if err := conn.QueryRowCtx(ctx, &resp, query, {{.lowerStartCamelField}}); err != nil { + return nil, err + } + return resp.{{.upperStartCamelPrimaryKey}}, nil + }, m.queryPrimary) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +}{{else}}var resp {{.upperStartCamelObject}} + query := fmt.Sprintf("select %s from %s where {{.originalField}} limit 1", {{.lowerStartCamelObject}}Rows, m.table ) + err := m.conn.QueryRowCtx(ctx, &resp, query, {{.lowerStartCamelField}}) + switch err { + case nil: + return &resp, nil + case sqlx.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +}{{end}} diff --git a/goctl_tpl/model/find-one.tpl b/goctl_tpl/model/find-one.tpl new file mode 100644 index 0000000..4f9319d --- /dev/null +++ b/goctl_tpl/model/find-one.tpl @@ -0,0 +1,26 @@ +func (m *default{{.upperStartCamelObject}}Model) FindOne(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) { + {{if .withCache}}{{.cacheKey}} + var resp {{.upperStartCamelObject}} + err := m.QueryRowCtx(ctx, &resp, {{.cacheKeyVariable}}, func(ctx context.Context, conn sqlx.SqlConn, v any) error { + query := fmt.Sprintf("select %s from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}} limit 1", {{.lowerStartCamelObject}}Rows, m.table) + return conn.QueryRowCtx(ctx, v, query, {{.lowerStartCamelPrimaryKey}}) + }) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + }{{else}}query := fmt.Sprintf("select %s from %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}} limit 1", {{.lowerStartCamelObject}}Rows, m.table) + var resp {{.upperStartCamelObject}} + err := m.conn.QueryRowCtx(ctx, &resp, query, {{.lowerStartCamelPrimaryKey}}) + switch err { + case nil: + return &resp, nil + case sqlx.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + }{{end}} +} diff --git a/goctl_tpl/model/import-no-cache.tpl b/goctl_tpl/model/import-no-cache.tpl new file mode 100644 index 0000000..0ffbc24 --- /dev/null +++ b/goctl_tpl/model/import-no-cache.tpl @@ -0,0 +1,14 @@ +import ( + "context" + "database/sql" + "fmt" + "strings" + {{if .time}}"time"{{end}} + + {{if .containsPQ}}"github.com/lib/pq"{{end}} + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" + + {{.third}} +) diff --git a/goctl_tpl/model/import.tpl b/goctl_tpl/model/import.tpl new file mode 100644 index 0000000..96650fd --- /dev/null +++ b/goctl_tpl/model/import.tpl @@ -0,0 +1,16 @@ +import ( + "context" + "database/sql" + "fmt" + "strings" + {{if .time}}"time"{{end}} + + {{if .containsPQ}}"github.com/lib/pq"{{end}} + "github.com/zeromicro/go-zero/core/stores/builder" + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlc" + "github.com/zeromicro/go-zero/core/stores/sqlx" + "github.com/zeromicro/go-zero/core/stringx" + + {{.third}} +) diff --git a/goctl_tpl/model/insert.tpl b/goctl_tpl/model/insert.tpl new file mode 100644 index 0000000..08e02bc --- /dev/null +++ b/goctl_tpl/model/insert.tpl @@ -0,0 +1,9 @@ +func (m *default{{.upperStartCamelObject}}Model) Insert(ctx context.Context, data *{{.upperStartCamelObject}}) (sql.Result,error) { + {{if .withCache}}{{.keys}} + ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("insert into %s (%s) values ({{.expression}})", m.table, {{.lowerStartCamelObject}}RowsExpectAutoSet) + return conn.ExecCtx(ctx, query, {{.expressionValues}}) + }, {{.keyValues}}){{else}}query := fmt.Sprintf("insert into %s (%s) values ({{.expression}})", m.table, {{.lowerStartCamelObject}}RowsExpectAutoSet) + ret,err:=m.conn.ExecCtx(ctx, query, {{.expressionValues}}){{end}} + return ret,err +} diff --git a/goctl_tpl/model/interface-delete.tpl b/goctl_tpl/model/interface-delete.tpl new file mode 100644 index 0000000..d10978b --- /dev/null +++ b/goctl_tpl/model/interface-delete.tpl @@ -0,0 +1 @@ +Delete(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) error \ No newline at end of file diff --git a/goctl_tpl/model/interface-find-one-by-field.tpl b/goctl_tpl/model/interface-find-one-by-field.tpl new file mode 100644 index 0000000..e18ded7 --- /dev/null +++ b/goctl_tpl/model/interface-find-one-by-field.tpl @@ -0,0 +1 @@ +FindOneBy{{.upperField}}(ctx context.Context, {{.in}}) (*{{.upperStartCamelObject}}, error) \ No newline at end of file diff --git a/goctl_tpl/model/interface-find-one.tpl b/goctl_tpl/model/interface-find-one.tpl new file mode 100644 index 0000000..a7a5440 --- /dev/null +++ b/goctl_tpl/model/interface-find-one.tpl @@ -0,0 +1 @@ +FindOne(ctx context.Context, {{.lowerStartCamelPrimaryKey}} {{.dataType}}) (*{{.upperStartCamelObject}}, error) \ No newline at end of file diff --git a/goctl_tpl/model/interface-insert.tpl b/goctl_tpl/model/interface-insert.tpl new file mode 100644 index 0000000..2872403 --- /dev/null +++ b/goctl_tpl/model/interface-insert.tpl @@ -0,0 +1 @@ +Insert(ctx context.Context, data *{{.upperStartCamelObject}}) (sql.Result,error) \ No newline at end of file diff --git a/goctl_tpl/model/interface-update.tpl b/goctl_tpl/model/interface-update.tpl new file mode 100644 index 0000000..1920425 --- /dev/null +++ b/goctl_tpl/model/interface-update.tpl @@ -0,0 +1 @@ +Update(ctx context.Context, {{if .containsIndexCache}}newData{{else}}data{{end}} *{{.upperStartCamelObject}}) error \ No newline at end of file diff --git a/goctl_tpl/model/model-gen.tpl b/goctl_tpl/model/model-gen.tpl new file mode 100644 index 0000000..ca6bbd1 --- /dev/null +++ b/goctl_tpl/model/model-gen.tpl @@ -0,0 +1,16 @@ +// Code generated by goctl. DO NOT EDIT. +// versions: +// goctl version: 1.9.2 + +package {{.pkg}} +{{.imports}} +{{.vars}} +{{.types}} +{{.new}} +{{.delete}} +{{.find}} +{{.insert}} +{{.update}} +{{.extraMethod}} +{{.tableName}} +{{.customized}} diff --git a/goctl_tpl/model/model-new.tpl b/goctl_tpl/model/model-new.tpl new file mode 100644 index 0000000..f6271cc --- /dev/null +++ b/goctl_tpl/model/model-new.tpl @@ -0,0 +1,7 @@ +func new{{.upperStartCamelObject}}Model(conn sqlx.SqlConn{{if .withCache}}, c cache.CacheConf, opts ...cache.Option{{end}}) *default{{.upperStartCamelObject}}Model { + return &default{{.upperStartCamelObject}}Model{ + {{if .withCache}}CachedConn: sqlc.NewConn(conn, c, opts...){{else}}conn:conn{{end}}, + table: {{.table}}, + } +} + diff --git a/goctl_tpl/model/model.tpl b/goctl_tpl/model/model.tpl new file mode 100644 index 0000000..d861da7 --- /dev/null +++ b/goctl_tpl/model/model.tpl @@ -0,0 +1,38 @@ +package {{.pkg}} +{{if .withCache}} +import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlx" +) +{{else}} + +import "github.com/zeromicro/go-zero/core/stores/sqlx" +{{end}} +var _ {{.upperStartCamelObject}}Model = (*custom{{.upperStartCamelObject}}Model)(nil) + +type ( + // {{.upperStartCamelObject}}Model is an interface to be customized, add more methods here, + // and implement the added methods in custom{{.upperStartCamelObject}}Model. + {{.upperStartCamelObject}}Model interface { + {{.lowerStartCamelObject}}Model + {{if not .withCache}}withSession(session sqlx.Session) {{.upperStartCamelObject}}Model{{end}} + } + + custom{{.upperStartCamelObject}}Model struct { + *default{{.upperStartCamelObject}}Model + } +) + +// New{{.upperStartCamelObject}}Model returns a model for the database table. +func New{{.upperStartCamelObject}}Model(conn sqlx.SqlConn{{if .withCache}}, c cache.CacheConf, opts ...cache.Option{{end}}) {{.upperStartCamelObject}}Model { + return &custom{{.upperStartCamelObject}}Model{ + default{{.upperStartCamelObject}}Model: new{{.upperStartCamelObject}}Model(conn{{if .withCache}}, c, opts...{{end}}), + } +} + +{{if not .withCache}} +func (m *custom{{.upperStartCamelObject}}Model) withSession(session sqlx.Session) {{.upperStartCamelObject}}Model { + return New{{.upperStartCamelObject}}Model(sqlx.NewSqlConnFromSession(session)) +} +{{end}} + diff --git a/goctl_tpl/model/table-name.tpl b/goctl_tpl/model/table-name.tpl new file mode 100644 index 0000000..8b14e33 --- /dev/null +++ b/goctl_tpl/model/table-name.tpl @@ -0,0 +1,3 @@ +func (m *default{{.upperStartCamelObject}}Model) tableName() string { + return m.table +} diff --git a/goctl_tpl/model/tag.tpl b/goctl_tpl/model/tag.tpl new file mode 100644 index 0000000..8e1ddf0 --- /dev/null +++ b/goctl_tpl/model/tag.tpl @@ -0,0 +1 @@ +`db:"{{.field}}"` \ No newline at end of file diff --git a/goctl_tpl/model/types.tpl b/goctl_tpl/model/types.tpl new file mode 100644 index 0000000..960cf2b --- /dev/null +++ b/goctl_tpl/model/types.tpl @@ -0,0 +1,14 @@ +type ( + {{.lowerStartCamelObject}}Model interface{ + {{.method}} + } + + default{{.upperStartCamelObject}}Model struct { + {{if .withCache}}sqlc.CachedConn{{else}}conn sqlx.SqlConn{{end}} + table string + } + + {{.upperStartCamelObject}} struct { + {{.fields}} + } +) diff --git a/goctl_tpl/model/update.tpl b/goctl_tpl/model/update.tpl new file mode 100644 index 0000000..41b9331 --- /dev/null +++ b/goctl_tpl/model/update.tpl @@ -0,0 +1,14 @@ +func (m *default{{.upperStartCamelObject}}Model) Update(ctx context.Context, {{if .containsIndexCache}}newData{{else}}data{{end}} *{{.upperStartCamelObject}}) error { + {{if .withCache}}{{if .containsIndexCache}}data, err:=m.FindOne(ctx, newData.{{.upperStartCamelPrimaryKey}}) + if err!=nil{ + return err + } + +{{end}} {{.keys}} + _, {{if .containsIndexCache}}err{{else}}err:{{end}}= m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table, {{.lowerStartCamelObject}}RowsWithPlaceHolder) + return conn.ExecCtx(ctx, query, {{.expressionValues}}) + }, {{.keyValues}}){{else}}query := fmt.Sprintf("update %s set %s where {{.originalPrimaryKey}} = {{if .postgreSql}}$1{{else}}?{{end}}", m.table, {{.lowerStartCamelObject}}RowsWithPlaceHolder) + _,err:=m.conn.ExecCtx(ctx, query, {{.expressionValues}}){{end}} + return err +} diff --git a/goctl_tpl/model/var.tpl b/goctl_tpl/model/var.tpl new file mode 100644 index 0000000..c11fe53 --- /dev/null +++ b/goctl_tpl/model/var.tpl @@ -0,0 +1,8 @@ +var ( +{{.lowerStartCamelObject}}FieldNames = builder.RawFieldNames(&{{.upperStartCamelObject}}{}{{if .postgreSql}}, true{{end}}) +{{.lowerStartCamelObject}}Rows = strings.Join({{.lowerStartCamelObject}}FieldNames, ",") +{{.lowerStartCamelObject}}RowsExpectAutoSet = {{if .postgreSql}}strings.Join(stringx.Remove({{.lowerStartCamelObject}}FieldNames, {{if .autoIncrement}}"{{.originalPrimaryKey}}", {{end}} {{.ignoreColumns}}), ","){{else}}strings.Join(stringx.Remove({{.lowerStartCamelObject}}FieldNames, {{if .autoIncrement}}"{{.originalPrimaryKey}}", {{end}} {{.ignoreColumns}}), ","){{end}} +{{.lowerStartCamelObject}}RowsWithPlaceHolder = {{if .postgreSql}}builder.PostgreSqlJoin(stringx.Remove({{.lowerStartCamelObject}}FieldNames, "{{.originalPrimaryKey}}", {{.ignoreColumns}})){{else}}strings.Join(stringx.Remove({{.lowerStartCamelObject}}FieldNames, "{{.originalPrimaryKey}}", {{.ignoreColumns}}), "=?,") + "=?"{{end}} + +{{if .withCache}}{{.cacheKeys}}{{end}} +) diff --git a/goctl_tpl/mongo/err.tpl b/goctl_tpl/mongo/err.tpl new file mode 100644 index 0000000..27d9244 --- /dev/null +++ b/goctl_tpl/mongo/err.tpl @@ -0,0 +1,12 @@ +package model + +import ( + "errors" + + "github.com/zeromicro/go-zero/core/stores/mon" +) + +var ( + ErrNotFound = mon.ErrNotFound + ErrInvalidObjectId = errors.New("invalid objectId") +) diff --git a/goctl_tpl/mongo/model.tpl b/goctl_tpl/mongo/model.tpl new file mode 100644 index 0000000..e26a94b --- /dev/null +++ b/goctl_tpl/mongo/model.tpl @@ -0,0 +1,79 @@ +// Code generated by goctl. DO NOT EDIT. +// goctl {{.version}} + +package model + +import ( + "context" + "time" + + {{if .Cache}}"github.com/zeromicro/go-zero/core/stores/monc"{{else}}"github.com/zeromicro/go-zero/core/stores/mon"{{end}} + "go.mongodb.org/mongo-driver/v2/bson" + "go.mongodb.org/mongo-driver/v2/mongo" +) + +{{if .Cache}}var prefix{{.Type}}CacheKey = "{{if .Prefix}}{{.Prefix}}:{{end}}cache:{{.lowerType}}:"{{end}} + +type {{.lowerType}}Model interface{ + Insert(ctx context.Context,data *{{.Type}}) error + FindOne(ctx context.Context,id string) (*{{.Type}}, error) + Update(ctx context.Context,data *{{.Type}}) (*mongo.UpdateResult, error) + Delete(ctx context.Context,id string) (int64, error) +} + +type default{{.Type}}Model struct { + conn {{if .Cache}}*monc.Model{{else}}*mon.Model{{end}} +} + +func newDefault{{.Type}}Model(conn {{if .Cache}}*monc.Model{{else}}*mon.Model{{end}}) *default{{.Type}}Model { + return &default{{.Type}}Model{conn: conn} +} + + +func (m *default{{.Type}}Model) Insert(ctx context.Context, data *{{.Type}}) error { + if data.ID.IsZero() { + data.ID = bson.NewObjectID() + data.CreateAt = time.Now() + data.UpdateAt = time.Now() + } + + {{if .Cache}}key := prefix{{.Type}}CacheKey + data.ID.Hex(){{end}} + _, err := m.conn.InsertOne(ctx, {{if .Cache}}key, {{end}} data) + return err +} + +func (m *default{{.Type}}Model) FindOne(ctx context.Context, id string) (*{{.Type}}, error) { + oid, err := bson.ObjectIDFromHex(id) + if err != nil { + return nil, ErrInvalidObjectId + } + + var data {{.Type}} + {{if .Cache}}key := prefix{{.Type}}CacheKey + id{{end}} + err = m.conn.FindOne(ctx, {{if .Cache}}key, {{end}}&data, bson.M{"_id": oid}) + switch err { + case nil: + return &data, nil + case {{if .Cache}}monc{{else}}mon{{end}}.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *default{{.Type}}Model) Update(ctx context.Context, data *{{.Type}}) (*mongo.UpdateResult, error) { + data.UpdateAt = time.Now() + {{if .Cache}}key := prefix{{.Type}}CacheKey + data.ID.Hex(){{end}} + res, err := m.conn.UpdateOne(ctx, {{if .Cache}}key, {{end}}bson.M{"_id": data.ID}, bson.M{"$set": data}) + return res, err +} + +func (m *default{{.Type}}Model) Delete(ctx context.Context, id string) (int64, error) { + oid, err := bson.ObjectIDFromHex(id) + if err != nil { + return 0, ErrInvalidObjectId + } + {{if .Cache}}key := prefix{{.Type}}CacheKey +id{{end}} + res, err := m.conn.DeleteOne(ctx, {{if .Cache}}key, {{end}}bson.M{"_id": oid}) + return res, err +} diff --git a/goctl_tpl/mongo/model_custom.tpl b/goctl_tpl/mongo/model_custom.tpl new file mode 100644 index 0000000..31fa865 --- /dev/null +++ b/goctl_tpl/mongo/model_custom.tpl @@ -0,0 +1,38 @@ +package model + +{{if .Cache}}import ( + "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/monc" +){{else}}import "github.com/zeromicro/go-zero/core/stores/mon"{{end}} + +{{if .Easy}} +const {{.Type}}CollectionName = "{{.snakeType}}" +{{end}} + +var _ {{.Type}}Model = (*custom{{.Type}}Model)(nil) + +type ( + // {{.Type}}Model is an interface to be customized, add more methods here, + // and implement the added methods in custom{{.Type}}Model. + {{.Type}}Model interface { + {{.lowerType}}Model + } + + custom{{.Type}}Model struct { + *default{{.Type}}Model + } +) + + +// New{{.Type}}Model returns a model for the mongo. +{{if .Easy}}func New{{.Type}}Model(url, db string{{if .Cache}}, c cache.CacheConf{{end}}) {{.Type}}Model { + conn := {{if .Cache}}monc{{else}}mon{{end}}.MustNewModel(url, db, {{.Type}}CollectionName{{if .Cache}}, c{{end}}) + return &custom{{.Type}}Model{ + default{{.Type}}Model: newDefault{{.Type}}Model(conn), + } +}{{else}}func New{{.Type}}Model(url, db, collection string{{if .Cache}}, c cache.CacheConf{{end}}) {{.Type}}Model { + conn := {{if .Cache}}monc{{else}}mon{{end}}.MustNewModel(url, db, collection{{if .Cache}}, c{{end}}) + return &custom{{.Type}}Model{ + default{{.Type}}Model: newDefault{{.Type}}Model(conn), + } +}{{end}} diff --git a/goctl_tpl/mongo/model_types.tpl b/goctl_tpl/mongo/model_types.tpl new file mode 100644 index 0000000..9f8c197 --- /dev/null +++ b/goctl_tpl/mongo/model_types.tpl @@ -0,0 +1,14 @@ +package model + +import ( + "time" + + "go.mongodb.org/mongo-driver/v2/bson" +) + +type {{.Type}} struct { + ID bson.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + // TODO: Fill your own fields + UpdateAt time.Time `bson:"updateAt,omitempty" json:"updateAt,omitempty"` + CreateAt time.Time `bson:"createAt,omitempty" json:"createAt,omitempty"` +} diff --git a/goctl_tpl/newapi/newtemplate.tpl b/goctl_tpl/newapi/newtemplate.tpl new file mode 100644 index 0000000..b677344 --- /dev/null +++ b/goctl_tpl/newapi/newtemplate.tpl @@ -0,0 +1,14 @@ +syntax = "v1" + +type Request { + Name string `path:"name,options=you|me"` +} + +type Response { + Message string `json:"message"` +} + +service {{.name}}-api { + @handler {{.handler}}Handler + get /from/:name(Request) returns (Response) +} diff --git a/goctl_tpl/rpc/call.tpl b/goctl_tpl/rpc/call.tpl new file mode 100644 index 0000000..27b4879 --- /dev/null +++ b/goctl_tpl/rpc/call.tpl @@ -0,0 +1,33 @@ +{{.head}} + +package {{.filePackage}} + +import ( + "context" + + {{.pbPackage}} + {{if ne .pbPackage .protoGoPackage}}{{.protoGoPackage}}{{end}} + + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" +) + +type ( + {{.alias}} + + {{.serviceName}} interface { + {{.interface}} + } + + default{{.serviceName}} struct { + cli zrpc.Client + } +) + +func New{{.serviceName}}(cli zrpc.Client) {{.serviceName}} { + return &default{{.serviceName}}{ + cli: cli, + } +} + +{{.functions}} diff --git a/goctl_tpl/rpc/config.tpl b/goctl_tpl/rpc/config.tpl new file mode 100644 index 0000000..c1f85b9 --- /dev/null +++ b/goctl_tpl/rpc/config.tpl @@ -0,0 +1,7 @@ +package config + +import "github.com/zeromicro/go-zero/zrpc" + +type Config struct { + zrpc.RpcServerConf +} diff --git a/goctl_tpl/rpc/etc.tpl b/goctl_tpl/rpc/etc.tpl new file mode 100644 index 0000000..6cd4bdd --- /dev/null +++ b/goctl_tpl/rpc/etc.tpl @@ -0,0 +1,6 @@ +Name: {{.serviceName}}.rpc +ListenOn: 0.0.0.0:8080 +Etcd: + Hosts: + - 127.0.0.1:2379 + Key: {{.serviceName}}.rpc diff --git a/goctl_tpl/rpc/logic-func.tpl b/goctl_tpl/rpc/logic-func.tpl new file mode 100644 index 0000000..e9410d4 --- /dev/null +++ b/goctl_tpl/rpc/logic-func.tpl @@ -0,0 +1,6 @@ +{{if .hasComment}}{{.comment}}{{end}} +func (l *{{.logicName}}) {{.method}} ({{if .hasReq}}in {{.request}}{{if .stream}},stream {{.streamBody}}{{end}}{{else}}stream {{.streamBody}}{{end}}) ({{if .hasReply}}{{.response}},{{end}} error) { + // todo: add your logic here and delete this line + + return {{if .hasReply}}&{{.responseType}}{},{{end}} nil +} diff --git a/goctl_tpl/rpc/logic.tpl b/goctl_tpl/rpc/logic.tpl new file mode 100644 index 0000000..b8d81f0 --- /dev/null +++ b/goctl_tpl/rpc/logic.tpl @@ -0,0 +1,24 @@ +package {{.packageName}} + +import ( + "context" + + {{.imports}} + + "github.com/zeromicro/go-zero/core/logx" +) + +type {{.logicName}} struct { + ctx context.Context + svcCtx *svc.ServiceContext + logx.Logger +} + +func New{{.logicName}}(ctx context.Context,svcCtx *svc.ServiceContext) *{{.logicName}} { + return &{{.logicName}}{ + ctx: ctx, + svcCtx: svcCtx, + Logger: logx.WithContext(ctx), + } +} +{{.functions}} diff --git a/goctl_tpl/rpc/main.tpl b/goctl_tpl/rpc/main.tpl new file mode 100644 index 0000000..566ad82 --- /dev/null +++ b/goctl_tpl/rpc/main.tpl @@ -0,0 +1,36 @@ +package main + +import ( + "flag" + "fmt" + + {{.imports}} + + "github.com/zeromicro/go-zero/core/conf" + "github.com/zeromicro/go-zero/core/service" + "github.com/zeromicro/go-zero/zrpc" + "google.golang.org/grpc" + "google.golang.org/grpc/reflection" +) + +var configFile = flag.String("f", "etc/{{.serviceName}}.yaml", "the config file") + +func main() { + flag.Parse() + + var c config.Config + conf.MustLoad(*configFile, &c) + ctx := svc.NewServiceContext(c) + + s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) { +{{range .serviceNames}} {{.Pkg}}.Register{{.GRPCService}}Server(grpcServer, {{.ServerPkg}}.New{{.Service}}Server(ctx)) +{{end}} + if c.Mode == service.DevMode || c.Mode == service.TestMode { + reflection.Register(grpcServer) + } + }) + defer s.Stop() + + fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) + s.Start() +} diff --git a/goctl_tpl/rpc/server-func.tpl b/goctl_tpl/rpc/server-func.tpl new file mode 100644 index 0000000..d771b43 --- /dev/null +++ b/goctl_tpl/rpc/server-func.tpl @@ -0,0 +1,6 @@ + +{{if .hasComment}}{{.comment}}{{end}} +func (s *{{.server}}Server) {{.method}} ({{if .notStream}}ctx context.Context,{{if .hasReq}} in {{.request}}{{end}}{{else}}{{if .hasReq}} in {{.request}},{{end}}stream {{.streamBody}}{{end}}) ({{if .notStream}}{{.response}},{{end}}error) { + l := {{.logicPkg}}.New{{.logicName}}({{if .notStream}}ctx,{{else}}stream.Context(),{{end}}s.svcCtx) + return l.{{.method}}({{if .hasReq}}in{{if .stream}} ,stream{{end}}{{else}}{{if .stream}}stream{{end}}{{end}}) +} diff --git a/goctl_tpl/rpc/server.tpl b/goctl_tpl/rpc/server.tpl new file mode 100644 index 0000000..84a2f9c --- /dev/null +++ b/goctl_tpl/rpc/server.tpl @@ -0,0 +1,22 @@ +{{.head}} + +package server + +import ( + {{if .notStream}}"context"{{end}} + + {{.imports}} +) + +type {{.server}}Server struct { + svcCtx *svc.ServiceContext + {{.unimplementedServer}} +} + +func New{{.server}}Server(svcCtx *svc.ServiceContext) *{{.server}}Server { + return &{{.server}}Server{ + svcCtx: svcCtx, + } +} + +{{.funcs}} diff --git a/goctl_tpl/rpc/svc.tpl b/goctl_tpl/rpc/svc.tpl new file mode 100644 index 0000000..cf2b47a --- /dev/null +++ b/goctl_tpl/rpc/svc.tpl @@ -0,0 +1,13 @@ +package svc + +import {{.imports}} + +type ServiceContext struct { + Config config.Config +} + +func NewServiceContext(c config.Config) *ServiceContext { + return &ServiceContext{ + Config:c, + } +} diff --git a/goctl_tpl/rpc/template.tpl b/goctl_tpl/rpc/template.tpl new file mode 100644 index 0000000..76daa94 --- /dev/null +++ b/goctl_tpl/rpc/template.tpl @@ -0,0 +1,16 @@ +syntax = "proto3"; + +package {{.package}}; +option go_package="./{{.package}}"; + +message Request { + string ping = 1; +} + +message Response { + string pong = 1; +} + +service {{.serviceName}} { + rpc Ping(Request) returns(Response); +} diff --git a/pkg/cryptox/aes.go b/pkg/cryptox/aes.go new file mode 100644 index 0000000..7743918 --- /dev/null +++ b/pkg/cryptox/aes.go @@ -0,0 +1,85 @@ +package cryptox + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/md5" + "crypto/sha256" + "encoding/base64" + "encoding/hex" + "fmt" + "time" +) + +// generateKey: SHA256(secret)[:32] +func generateKey(secret string) []byte { + h := sha256.Sum256([]byte(secret)) + return h[:32] +} + +// generateIv: SHA256(hex(md5(nonce)) + secret)[:16] +func generateIv(nonce, secret string) []byte { + md5h := md5.Sum([]byte(nonce)) + md5hex := hex.EncodeToString(md5h[:]) + sha := sha256.Sum256([]byte(md5hex + secret)) + return sha[:16] +} + +// Encrypt 加密明文,返回 base64密文 和 nonce(hex(UnixNano)) +func Encrypt(plaintext []byte, secret string) (dataB64 string, nonce string, err error) { + nonce = fmt.Sprintf("%x", time.Now().UnixNano()) + key := generateKey(secret) + iv := generateIv(nonce, secret) + + block, err := aes.NewCipher(key) + if err != nil { + return + } + padded := pkcs7Pad(plaintext, aes.BlockSize) + mode := cipher.NewCBCEncrypter(block, iv) + dst := make([]byte, len(padded)) + mode.CryptBlocks(dst, padded) + dataB64 = base64.StdEncoding.EncodeToString(dst) + return +} + +// Decrypt 解密,nonce 用于派生 IV +func Decrypt(dataB64, secret, nonce string) ([]byte, error) { + ciphertext, err := base64.StdEncoding.DecodeString(dataB64) + if err != nil { + return nil, err + } + key := generateKey(secret) + iv := generateIv(nonce, secret) + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + if len(ciphertext)%aes.BlockSize != 0 { + return nil, fmt.Errorf("ciphertext length not multiple of block size") + } + mode := cipher.NewCBCDecrypter(block, iv) + dst := make([]byte, len(ciphertext)) + mode.CryptBlocks(dst, ciphertext) + return pkcs7Unpad(dst) +} + +func pkcs7Pad(data []byte, blockSize int) []byte { + pad := blockSize - len(data)%blockSize + padding := make([]byte, pad) + for i := range padding { + padding[i] = byte(pad) + } + return append(data, padding...) +} + +func pkcs7Unpad(data []byte) ([]byte, error) { + if len(data) == 0 { + return nil, fmt.Errorf("empty data") + } + pad := int(data[len(data)-1]) + if pad == 0 || pad > aes.BlockSize { + return nil, fmt.Errorf("invalid padding size: %d", pad) + } + return data[:len(data)-pad], nil +} diff --git a/pkg/cryptox/aes_test.go b/pkg/cryptox/aes_test.go new file mode 100644 index 0000000..734a5c6 --- /dev/null +++ b/pkg/cryptox/aes_test.go @@ -0,0 +1,34 @@ +package cryptox + +import ( + "testing" +) + +func TestEncryptDecryptRoundtrip(t *testing.T) { + secret := "test-secret-key" + plain := []byte(`{"user_id":1,"action":"login"}`) + dataB64, nonce, err := Encrypt(plain, secret) + if err != nil { + t.Fatal(err) + } + got, err := Decrypt(dataB64, secret, nonce) + if err != nil { + t.Fatal(err) + } + if string(got) != string(plain) { + t.Fatalf("roundtrip mismatch: got %s", got) + } +} + +func TestDecryptWrongNonce(t *testing.T) { + secret := "test-secret-key" + plain := []byte(`{"foo":"bar"}`) + dataB64, _, err := Encrypt(plain, secret) + if err != nil { + t.Fatal(err) + } + _, err = Decrypt(dataB64, secret, "wrongnonce") + if err == nil { + t.Fatal("expected error with wrong nonce") + } +} diff --git a/pkg/cryptox/password.go b/pkg/cryptox/password.go new file mode 100644 index 0000000..96f2108 --- /dev/null +++ b/pkg/cryptox/password.go @@ -0,0 +1,15 @@ +package cryptox + +import "golang.org/x/crypto/bcrypt" + +// CheckPasswordHash 检查密码和 Hash 是否匹配 +func CheckPasswordHash(password, hash string) bool { + err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) + return err == nil +} + +// GeneratePasswordHash 生成密码的 Hash +func GeneratePasswordHash(password string) (string, error) { + bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) + return string(bytes), err +} diff --git a/pkg/result/response.go b/pkg/result/response.go index d93d9f3..b023abd 100644 --- a/pkg/result/response.go +++ b/pkg/result/response.go @@ -3,7 +3,10 @@ package result import ( "net/http" + "github.com/zero-ppanel/zero-ppanel/pkg/xerr" + "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/rest/httpx" + "google.golang.org/grpc/status" ) type Response struct { @@ -23,3 +26,44 @@ func Error(code int, msg string) *Response { func OkJson(w http.ResponseWriter, data interface{}) { httpx.OkJson(w, Success(data)) } + +func Parse(r *http.Request, v interface{}) error { + return httpx.Parse(r, v) +} + +// HttpResult global HTTP error handler +func HttpResult(r *http.Request, w http.ResponseWriter, resp interface{}, err error) { + if err == nil { + httpx.WriteJson(w, http.StatusOK, Success(resp)) + return + } + + code, res := ErrHandler(err) + logx.WithContext(r.Context()).Errorf("【API-ERR】 : %+v ", err) + httpx.WriteJson(w, code, res) +} + +// ErrHandler 按照 go-zero 开发规范,处理全局错误 +func ErrHandler(err error) (int, any) { + errCode := xerr.ServerError + errMsg := xerr.MapErrMsg(errCode) + + // 直接从错误中提取自定义代码和消息 + // 不进行过度包装,直接判定是否满足业务错误特征 + if e, ok := err.(interface{ + GetErrCode() int + GetErrMsg() string + }); ok { + errCode = e.GetErrCode() + errMsg = e.GetErrMsg() + } else if gstatus, ok := status.FromError(err); ok { + // 识别 gRPC 错误 + grpcCode := uint32(gstatus.Code()) + if xerr.IsCodeErr(grpcCode) { + errCode = int(grpcCode) + errMsg = gstatus.Message() + } + } + + return http.StatusOK, Error(errCode, errMsg) +} diff --git a/pkg/signature/canonical.go b/pkg/signature/canonical.go new file mode 100644 index 0000000..239c801 --- /dev/null +++ b/pkg/signature/canonical.go @@ -0,0 +1,51 @@ +package signature + +import ( + "crypto/sha256" + "fmt" + "net/url" + "sort" + "strings" +) + +// BuildStringToSign 构造待签字符串 +// StringToSign = METHOD\nPATH\nCANONICAL_QUERY\nBODY_SHA256\nX-App-Id\nX-Timestamp\nX-Nonce +func BuildStringToSign(method, path, rawQuery string, body []byte, appId, timestamp, nonce string) string { + canonical := canonicalQuery(rawQuery) + bodyHash := sha256Hex(body) + parts := []string{ + strings.ToUpper(method), + path, + canonical, + bodyHash, + appId, + timestamp, + nonce, + } + return strings.Join(parts, "\n") +} + +func canonicalQuery(rawQuery string) string { + if rawQuery == "" { + return "" + } + values, err := url.ParseQuery(rawQuery) + if err != nil { + return rawQuery + } + keys := make([]string, 0, len(values)) + for k := range values { + keys = append(keys, k) + } + sort.Strings(keys) + parts := make([]string, 0, len(keys)) + for _, k := range keys { + parts = append(parts, fmt.Sprintf("%s=%s", k, values.Get(k))) + } + return strings.Join(parts, "&") +} + +func sha256Hex(data []byte) string { + h := sha256.Sum256(data) + return fmt.Sprintf("%x", h) +} diff --git a/pkg/signature/config.go b/pkg/signature/config.go new file mode 100644 index 0000000..9a25b37 --- /dev/null +++ b/pkg/signature/config.go @@ -0,0 +1,7 @@ +package signature + +type SignatureConf struct { + AppSecrets map[string]string + ValidWindowSeconds int64 // 默认 300 + SkipPrefixes []string +} diff --git a/pkg/signature/errors.go b/pkg/signature/errors.go new file mode 100644 index 0000000..793fad4 --- /dev/null +++ b/pkg/signature/errors.go @@ -0,0 +1,10 @@ +package signature + +import "errors" + +var ( + ErrSignatureMissing = errors.New("signature missing") + ErrSignatureExpired = errors.New("signature expired") + ErrSignatureInvalid = errors.New("signature invalid") + ErrSignatureReplay = errors.New("signature replay") +) diff --git a/pkg/signature/nonce_store.go b/pkg/signature/nonce_store.go new file mode 100644 index 0000000..4dbf170 --- /dev/null +++ b/pkg/signature/nonce_store.go @@ -0,0 +1,32 @@ +package signature + +import ( + "context" + + "github.com/zeromicro/go-zero/core/stores/redis" +) + +// NonceStore 防重放存储接口 +type NonceStore interface { + // SetIfNotExists 返回 (true, nil) 表示 key 已存在(重放攻击) + SetIfNotExists(ctx context.Context, appId, nonce string, ttlSeconds int64) (bool, error) +} + +type RedisNonceStore struct { + client *redis.Redis +} + +func NewRedisNonceStore(client *redis.Redis) *RedisNonceStore { + return &RedisNonceStore{client: client} +} + +func (s *RedisNonceStore) SetIfNotExists(_ context.Context, appId, nonce string, ttlSeconds int64) (bool, error) { + key := "sig:nonce:" + appId + ":" + nonce + // go-zero redis.Redis.SetNX 返回 true 表示设置成功(首次) + ok, err := s.client.SetnxEx(key, "1", int(ttlSeconds)) + if err != nil { + return false, err + } + // SetnxEx ok=true 首次,ok=false 已存在(重放) + return !ok, nil +} diff --git a/pkg/signature/signature_test.go b/pkg/signature/signature_test.go new file mode 100644 index 0000000..5c0119b --- /dev/null +++ b/pkg/signature/signature_test.go @@ -0,0 +1,105 @@ +package signature + +import ( + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "fmt" + "strconv" + "testing" + "time" +) + +// mockNonceStore 内存实现,用于测试 +type mockNonceStore struct { + seen map[string]bool +} + +func newMockStore() *mockNonceStore { + return &mockNonceStore{seen: map[string]bool{}} +} + +func (m *mockNonceStore) SetIfNotExists(_ context.Context, appId, nonce string, _ int64) (bool, error) { + key := appId + ":" + nonce + if m.seen[key] { + return true, nil + } + m.seen[key] = true + return false, nil +} + +func makeSignature(secret, stringToSign string) string { + mac := hmac.New(sha256.New, []byte(secret)) + mac.Write([]byte(stringToSign)) + return hex.EncodeToString(mac.Sum(nil)) +} + +func TestValidate_Success(t *testing.T) { + conf := SignatureConf{ + AppSecrets: map[string]string{"web-client": "uB4G,XxL2{7b"}, + ValidWindowSeconds: 300, + } + v := NewValidator(conf, newMockStore()) + + ts := strconv.FormatInt(time.Now().Unix(), 10) + nonce := fmt.Sprintf("%x", time.Now().UnixNano()) + sts := BuildStringToSign("POST", "/api/v1/order", "", []byte(`{"plan_id":1}`), "web-client", ts, nonce) + sig := makeSignature("uB4G,XxL2{7b", sts) + + if err := v.Validate(context.Background(), "web-client", ts, nonce, sig, sts); err != nil { + t.Fatal(err) + } +} + +func TestValidate_Expired(t *testing.T) { + conf := SignatureConf{ + AppSecrets: map[string]string{"web-client": "uB4G,XxL2{7b"}, + ValidWindowSeconds: 300, + } + v := NewValidator(conf, newMockStore()) + + ts := strconv.FormatInt(time.Now().Unix()-400, 10) // 已过期 400s + nonce := "abc" + sts := BuildStringToSign("GET", "/api/v1/user/info", "", nil, "web-client", ts, nonce) + sig := makeSignature("uB4G,XxL2{7b", sts) + + if err := v.Validate(context.Background(), "web-client", ts, nonce, sig, sts); err != ErrSignatureExpired { + t.Fatalf("expected ErrSignatureExpired, got %v", err) + } +} + +func TestValidate_Replay(t *testing.T) { + conf := SignatureConf{ + AppSecrets: map[string]string{"web-client": "uB4G,XxL2{7b"}, + ValidWindowSeconds: 300, + } + store := newMockStore() + v := NewValidator(conf, store) + + ts := strconv.FormatInt(time.Now().Unix(), 10) + nonce := "same-nonce-replay" + sts := BuildStringToSign("GET", "/api/v1/user/info", "", nil, "web-client", ts, nonce) + sig := makeSignature("uB4G,XxL2{7b", sts) + + _ = v.Validate(context.Background(), "web-client", ts, nonce, sig, sts) + if err := v.Validate(context.Background(), "web-client", ts, nonce, sig, sts); err != ErrSignatureReplay { + t.Fatalf("expected ErrSignatureReplay, got %v", err) + } +} + +func TestValidate_InvalidSignature(t *testing.T) { + conf := SignatureConf{ + AppSecrets: map[string]string{"web-client": "uB4G,XxL2{7b"}, + ValidWindowSeconds: 300, + } + v := NewValidator(conf, newMockStore()) + + ts := strconv.FormatInt(time.Now().Unix(), 10) + nonce := "nonce-invalid-sig" + sts := BuildStringToSign("POST", "/api/v1/order", "", []byte(`{"plan_id":1}`), "web-client", ts, nonce) + + if err := v.Validate(context.Background(), "web-client", ts, nonce, "badsignature", sts); err != ErrSignatureInvalid { + t.Fatalf("expected ErrSignatureInvalid, got %v", err) + } +} diff --git a/pkg/signature/validator.go b/pkg/signature/validator.go new file mode 100644 index 0000000..47a56e3 --- /dev/null +++ b/pkg/signature/validator.go @@ -0,0 +1,64 @@ +package signature + +import ( + "context" + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "strconv" + "time" +) + +// Validator 验证签名 +type Validator struct { + conf SignatureConf + nonceStore NonceStore +} + +func NewValidator(conf SignatureConf, store NonceStore) *Validator { + return &Validator{conf: conf, nonceStore: store} +} + +func (v *Validator) windowSeconds() int64 { + if v.conf.ValidWindowSeconds <= 0 { + return 300 + } + return v.conf.ValidWindowSeconds +} + +// Validate 验证请求签名,返回具体错误便于调用方映射到 xerr 错误码 +func (v *Validator) Validate(ctx context.Context, appId, timestamp, nonce, signature, stringToSign string) error { + // 1. appId 是否存在 + secret, ok := v.conf.AppSecrets[appId] + if !ok { + return ErrSignatureMissing + } + + // 2. 时间窗口 + ts, err := strconv.ParseInt(timestamp, 10, 64) + if err != nil { + return ErrSignatureExpired + } + diff := time.Now().Unix() - ts + if diff < 0 { + diff = -diff + } + if diff > v.windowSeconds() { + return ErrSignatureExpired + } + + // 3. Nonce 防重放(Redis 不可用时降级,仅时间窗口) + replayed, err := v.nonceStore.SetIfNotExists(ctx, appId, nonce, v.windowSeconds()+60) + if err == nil && replayed { + return ErrSignatureReplay + } + + // 4. HMAC 验签(防时序攻击) + mac := hmac.New(sha256.New, []byte(secret)) + mac.Write([]byte(stringToSign)) + expected := hex.EncodeToString(mac.Sum(nil)) + if !hmac.Equal([]byte(expected), []byte(signature)) { + return ErrSignatureInvalid + } + return nil +} diff --git a/pkg/xerr/errcode.go b/pkg/xerr/errcode.go index d37dbe6..380f55d 100644 --- a/pkg/xerr/errcode.go +++ b/pkg/xerr/errcode.go @@ -19,4 +19,9 @@ const ( PaymentFailed = 4001 SubscribeExpired = 5001 NodeAuthFailed = 6001 + SignatureMissing = 7001 + SignatureExpired = 7002 + SignatureInvalid = 7003 + SignatureReplay = 7004 + DecryptFailed = 7005 ) diff --git a/pkg/xerr/errmsg.go b/pkg/xerr/errmsg.go index eed3d84..7afc016 100644 --- a/pkg/xerr/errmsg.go +++ b/pkg/xerr/errmsg.go @@ -19,6 +19,18 @@ var codeText = map[int]string{ PaymentFailed: "支付失败", SubscribeExpired: "订阅已过期", NodeAuthFailed: "节点认证失败", + SignatureMissing: "缺少签名头", + SignatureExpired: "签名已过期", + SignatureInvalid: "签名错误", + SignatureReplay: "重放攻击", + DecryptFailed: "解密失败", +} + +func IsCodeErr(errcode uint32) bool { + if _, ok := codeText[int(errcode)]; ok { + return true + } + return false } func MapErrMsg(code int) string { diff --git a/pkg/xerr/errors.go b/pkg/xerr/errors.go new file mode 100644 index 0000000..36a7d1a --- /dev/null +++ b/pkg/xerr/errors.go @@ -0,0 +1,39 @@ +package xerr + +import "fmt" + +// ICodeError 定义业务错误接口,用于跨包识别 +type ICodeError interface { + GetErrCode() int + GetErrMsg() string +} + +type CodeError struct { + errCode int + errMsg string +} + +// 错误返回的 Error() 方法 +func (e *CodeError) Error() string { + return fmt.Sprintf("ErrCode:%d,ErrMsg:%s", e.errCode, e.errMsg) +} + +func (e *CodeError) GetErrCode() int { + return e.errCode +} + +func (e *CodeError) GetErrMsg() string { + return e.errMsg +} + +func NewErrCodeMsg(errCode int, errMsg string) *CodeError { + return &CodeError{errCode: errCode, errMsg: errMsg} +} + +func NewErrCode(errCode int) *CodeError { + return &CodeError{errCode: errCode, errMsg: MapErrMsg(errCode)} +} + +func NewErrMsg(errMsg string) *CodeError { + return &CodeError{errCode: ServerError, errMsg: errMsg} +}