From 34ecfd283d90505ce0c6de66324f034694bcd05f Mon Sep 17 00:00:00 2001 From: hawklin2017 <32898629+hawklin2017@users.noreply.github.com> Date: Mon, 30 Mar 2026 16:24:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=9B=BE=E7=89=87=E9=AA=8C?= =?UTF-8?q?=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/goreleaser.yaml | 12 ++ cmd/openim-rpc/openim-rpc-captcha/main.go | 12 ++ config/openim-rpc-captcha.yml | 12 ++ config/share.yml | 1 + go.mod | 6 +- go.sum | 6 + internal/api/captcha.go | 49 +++++++ internal/api/init.go | 1 + internal/api/router.go | 12 ++ internal/rpc/captcha/captcha.go | 158 ++++++++++++++++++++++ magefile.go | 26 ++++ pkg/common/cmd/constant.go | 6 +- pkg/common/cmd/rpc_captcha.go | 47 +++++++ pkg/common/config/config.go | 19 +++ start-config.yml | 1 + 15 files changed, 366 insertions(+), 2 deletions(-) create mode 100644 cmd/openim-rpc/openim-rpc-captcha/main.go create mode 100644 config/openim-rpc-captcha.yml create mode 100644 internal/api/captcha.go create mode 100644 internal/rpc/captcha/captcha.go create mode 100644 pkg/common/cmd/rpc_captcha.go diff --git a/build/goreleaser.yaml b/build/goreleaser.yaml index c24fb65da..e5b49f7ee 100644 --- a/build/goreleaser.yaml +++ b/build/goreleaser.yaml @@ -122,6 +122,17 @@ builds: - amd64 - arm64 + - binary: openim-rpc-captcha + id: openim-rpc-captcha + main: ./cmd/openim-rpc/openim-rpc-captcha/main.go + goos: + - darwin + - windows + - linux + goarch: + - amd64 + - arm64 + - binary: openim-rpc-conversation id: openim-rpc-conversation main: ./cmd/openim-rpc/openim-rpc-conversation/main.go @@ -355,6 +366,7 @@ nfpms: - openim-msgtransfer - openim-push - openim-rpc-auth + - openim-rpc-captcha - openim-rpc-conversation - openim-rpc-friend - openim-rpc-group diff --git a/cmd/openim-rpc/openim-rpc-captcha/main.go b/cmd/openim-rpc/openim-rpc-captcha/main.go new file mode 100644 index 000000000..8a3e9a938 --- /dev/null +++ b/cmd/openim-rpc/openim-rpc-captcha/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/openimsdk/open-im-server/v3/pkg/common/cmd" + "github.com/openimsdk/tools/system/program" +) + +func main() { + if err := cmd.NewCaptchaRpcCmd().Exec(); err != nil { + program.ExitWithError(err) + } +} diff --git a/config/openim-rpc-captcha.yml b/config/openim-rpc-captcha.yml new file mode 100644 index 000000000..a58453b3a --- /dev/null +++ b/config/openim-rpc-captcha.yml @@ -0,0 +1,12 @@ +rpc: + registerIP: "" + listenIP: 0.0.0.0 + autoSetPorts: false + ports: [10520] + +prometheus: + enable: false + ports: [12520] + +verifyPadding: 8 +expireSeconds: 120 diff --git a/config/share.yml b/config/share.yml index 916df78c4..64ce4c6f6 100644 --- a/config/share.yml +++ b/config/share.yml @@ -9,6 +9,7 @@ rpcRegisterName: auth: auth conversation: conversation third: third + captcha: captcha imAdminUserID: [ imAdmin ] diff --git a/go.mod b/go.mod index 3e996b857..1b7077cff 100644 --- a/go.mod +++ b/go.mod @@ -102,6 +102,7 @@ require ( github.com/go-openapi/swag v0.22.4 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-zookeeper/zk v1.0.3 // indirect + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -171,6 +172,7 @@ require ( github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/wenlng/go-captcha/v2 v2.0.5 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect @@ -191,7 +193,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.7.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/image v0.15.0 // indirect + golang.org/x/image v0.16.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/oauth2 v0.25.0 // indirect golang.org/x/sys v0.42.0 // indirect @@ -226,3 +228,5 @@ require ( golang.org/x/crypto v0.32.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) + +replace github.com/openimsdk/protocol => ./protocol diff --git a/go.sum b/go.sum index e9677acb9..cf0dd1b92 100644 --- a/go.sum +++ b/go.sum @@ -178,6 +178,8 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -450,6 +452,8 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/wenlng/go-captcha/v2 v2.0.5 h1:+1FpVwJZmLCqEHxOt+HvpUArFGo107nRxOeRVHkZhTc= +github.com/wenlng/go-captcha/v2 v2.0.5/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -518,6 +522,8 @@ golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjs golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw= +golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/internal/api/captcha.go b/internal/api/captcha.go new file mode 100644 index 000000000..9cedb3d3e --- /dev/null +++ b/internal/api/captcha.go @@ -0,0 +1,49 @@ +package api + +import ( + "github.com/gin-gonic/gin" + pbcaptcha "github.com/openimsdk/protocol/captcha" + "github.com/openimsdk/tools/a2r" + "github.com/openimsdk/tools/apiresp" + "github.com/openimsdk/tools/log" +) + +type CaptchaApi struct { + Client pbcaptcha.CaptchaClient +} + +func NewCaptchaApi(client pbcaptcha.CaptchaClient) *CaptchaApi { + return &CaptchaApi{Client: client} +} + +func (c *CaptchaApi) GenerateCaptcha(ctx *gin.Context) { + req, err := a2r.ParseRequestNotCheck[pbcaptcha.GenerateCaptchaReq](ctx) + if err != nil { + log.ZError(ctx, "captcha generate request parse failed", err) + apiresp.GinError(ctx, err) + return + } + resp, err := c.Client.GenerateCaptcha(ctx, req) + if err != nil { + log.ZError(ctx, "captcha generate rpc failed", err) + apiresp.GinError(ctx, err) + return + } + apiresp.GinSuccess(ctx, resp) +} + +func (c *CaptchaApi) VerifyCaptcha(ctx *gin.Context) { + req, err := a2r.ParseRequestNotCheck[pbcaptcha.VerifyCaptchaReq](ctx) + if err != nil { + log.ZError(ctx, "captcha verify request parse failed", err) + apiresp.GinError(ctx, err) + return + } + resp, err := c.Client.VerifyCaptcha(ctx, req) + if err != nil { + log.ZError(ctx, "captcha verify rpc failed", err, "captchaID", req.GetCaptchaID(), "x", req.GetX(), "y", req.GetY()) + apiresp.GinError(ctx, err) + return + } + apiresp.GinSuccess(ctx, resp) +} diff --git a/internal/api/init.go b/internal/api/init.go index 3fb5364f3..fb084b914 100644 --- a/internal/api/init.go +++ b/internal/api/init.go @@ -46,6 +46,7 @@ func Start(ctx context.Context, index int, cfg *Config) error { // Determine whether zk is passed according to whether it is a clustered deployment client, err = kdisc.NewDiscoveryRegister(&cfg.Discovery, &cfg.Share, []string{ cfg.Share.RpcRegisterName.MessageGateway, + cfg.Share.RpcRegisterName.Captcha, }) if err != nil { return errs.WrapMsg(err, "failed to register discovery service") diff --git a/internal/api/router.go b/internal/api/router.go index bad891fda..2fd19dec7 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -7,6 +7,7 @@ import ( "github.com/openimsdk/open-im-server/v3/pkg/rpcli" pbAuth "github.com/openimsdk/protocol/auth" + pbcaptcha "github.com/openimsdk/protocol/captcha" "github.com/openimsdk/protocol/conversation" "github.com/openimsdk/protocol/group" "github.com/openimsdk/protocol/msg" @@ -81,6 +82,10 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co if err != nil { return nil, err } + captchaConn, err := client.GetConn(ctx, config.Share.RpcRegisterName.Captcha) + if err != nil { + return nil, err + } gin.SetMode(gin.ReleaseMode) r := gin.New() if v, ok := binding.Validator.Engine().(*validator.Validate); ok { @@ -98,6 +103,7 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co r.Use(prommetricsGin(), gin.RecoveryWithWriter(gin.DefaultErrorWriter, mw.GinPanicErr), mw.CorsHandler(), mw.GinParseOperationID(), GinParseToken(rpcli.NewAuthClient(authConn))) u := NewUserApi(user.NewUserClient(userConn), client, config.Share.RpcRegisterName) m := NewMessageApi(msg.NewMsgClient(msgConn), rpcli.NewUserClient(userConn), config.Share.IMAdminUserID) + cp := NewCaptchaApi(pbcaptcha.NewCaptchaClient(captchaConn)) userRouterGroup := r.Group("/user") { userRouterGroup.POST("/user_register", u.UserRegister) @@ -264,6 +270,12 @@ func newGinRouter(ctx context.Context, client discovery.SvcDiscoveryRegistry, co conversationGroup.POST("/get_pinned_conversation_ids", c.GetPinnedConversationIDs) } + { + captchaGroup := r.Group("/captcha") + captchaGroup.POST("/generate", cp.GenerateCaptcha) + captchaGroup.POST("/verify", cp.VerifyCaptcha) + } + { statisticsGroup := r.Group("/statistics") statisticsGroup.POST("/user/register", u.UserRegisterCount) diff --git a/internal/rpc/captcha/captcha.go b/internal/rpc/captcha/captcha.go new file mode 100644 index 000000000..5d6b38c0a --- /dev/null +++ b/internal/rpc/captcha/captcha.go @@ -0,0 +1,158 @@ +package captcha + +import ( + "context" + "errors" + "time" + + "github.com/google/uuid" + "github.com/openimsdk/open-im-server/v3/pkg/common/config" + "github.com/openimsdk/open-im-server/v3/pkg/common/servererrs" + pbcaptcha "github.com/openimsdk/protocol/captcha" + "github.com/openimsdk/tools/db/mongoutil" + "github.com/openimsdk/tools/discovery" + "github.com/openimsdk/tools/log" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "google.golang.org/grpc" + + "github.com/wenlng/go-captcha/v2/base/option" + "github.com/wenlng/go-captcha/v2/slide" +) + +type Config struct { + RpcConfig config.Captcha + MongodbConfig config.Mongo + Share config.Share + Discovery config.Discovery +} + +type server struct { + pbcaptcha.UnimplementedCaptchaServer + conf config.Captcha + capt slide.Captcha + collection *mongo.Collection +} + +type captchaDoc struct { + CaptchaID string `bson:"captcha_id"` + X int `bson:"x"` + Y int `bson:"y"` + ExpiredAt time.Time `bson:"expired_at"` + CreateTime time.Time `bson:"create_time"` + VerifyTime time.Time `bson:"verify_time,omitempty"` +} + +func Start(ctx context.Context, cfg *Config, _ discovery.SvcDiscoveryRegistry, grpcServer *grpc.Server) error { + mongoClient, err := mongoutil.NewMongoDB(ctx, cfg.MongodbConfig.Build()) + if err != nil { + log.ZError(ctx, "captcha connect mongodb failed", err) + return err + } + collection := mongoClient.GetDB().Collection("captcha") + _, err = collection.Indexes().CreateMany(ctx, []mongo.IndexModel{ + { + Keys: bson.D{{Key: "captcha_id", Value: 1}}, + Options: options.Index().SetUnique(true), + }, + { + Keys: bson.D{{Key: "expired_at", Value: 1}}, + Options: options.Index().SetExpireAfterSeconds(0), + }, + }) + if err != nil { + log.ZError(ctx, "captcha create mongodb indexes failed", err) + return err + } + + s := &server{ + conf: cfg.RpcConfig, + capt: slide.NewBuilder().Make(), + collection: collection, + } + if s.conf.ExpireSeconds <= 0 { + s.conf.ExpireSeconds = 120 + } + if s.conf.VerifyPadding <= 0 { + s.conf.VerifyPadding = 8 + } + pbcaptcha.RegisterCaptchaServer(grpcServer, s) + return nil +} + +func (s *server) GenerateCaptcha(ctx context.Context, _ *pbcaptcha.GenerateCaptchaReq) (*pbcaptcha.GenerateCaptchaResp, error) { + captData, err := s.capt.Generate() + if err != nil { + log.ZError(ctx, "captcha generate failed", err) + return nil, err + } + block := captData.GetData() + masterImage, err := captData.GetMasterImage().ToBase64DataWithQuality(option.QualityNone) + if err != nil { + log.ZError(ctx, "captcha encode master image failed", err) + return nil, err + } + tileImage, err := captData.GetTileImage().ToBase64Data() + if err != nil { + log.ZError(ctx, "captcha encode tile image failed", err) + return nil, err + } + id := uuid.NewString() + now := time.Now() + expiredAt := now.Add(time.Duration(s.conf.ExpireSeconds) * time.Second) + _, err = s.collection.InsertOne(ctx, captchaDoc{ + CaptchaID: id, + X: block.X, + Y: block.Y, + ExpiredAt: expiredAt, + CreateTime: now, + }) + if err != nil { + log.ZError(ctx, "captcha insert mongodb failed", err, "captchaID", id) + return nil, err + } + return &pbcaptcha.GenerateCaptchaResp{ + CaptchaID: id, + MasterImage: masterImage, + TileImage: tileImage, + ExpireAt: expiredAt.Unix(), + }, nil +} + +func (s *server) VerifyCaptcha(ctx context.Context, req *pbcaptcha.VerifyCaptchaReq) (*pbcaptcha.VerifyCaptchaResp, error) { + now := time.Now() + filter := bson.M{ + "captcha_id": req.CaptchaID, + "verify_time": bson.M{"$exists": false}, + } + update := bson.M{ + "$set": bson.M{ + "verify_time": now, + }, + } + var doc captchaDoc + err := s.collection.FindOneAndUpdate( + ctx, + filter, + update, + options.FindOneAndUpdate().SetReturnDocument(options.Before), + ).Decode(&doc) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + log.ZWarn(ctx, "captcha not found or already verified", err, "captchaID", req.CaptchaID) + return nil, servererrs.ErrRecordNotFound.WrapMsg("captcha not found, expired, or already verified", "captchaID", req.CaptchaID) + } + log.ZError(ctx, "captcha verify query failed", err, "captchaID", req.CaptchaID) + return nil, servererrs.ErrDatabase.WrapMsg("verify captcha query failed", "captchaID", req.CaptchaID) + } + if now.After(doc.ExpiredAt) { + log.ZWarn(ctx, "captcha expired", nil, "captchaID", req.CaptchaID, "expiredAt", doc.ExpiredAt.Unix()) + return nil, servererrs.ErrFileUploadedExpired.WrapMsg("captcha expired", "captchaID", req.CaptchaID) + } + success := slide.Validate(int(req.X), int(req.Y), doc.X, doc.Y, s.conf.VerifyPadding) + if !success { + log.ZWarn(ctx, "captcha validate failed", nil, "captchaID", req.CaptchaID, "x", req.X, "y", req.Y) + } + return &pbcaptcha.VerifyCaptchaResp{Success: success}, nil +} diff --git a/magefile.go b/magefile.go index 9b34dfa60..3d76fa212 100644 --- a/magefile.go +++ b/magefile.go @@ -8,6 +8,7 @@ import ( "fmt" "os" + "github.com/magefile/mage/sh" "github.com/openimsdk/gomake/mageutil" "github.com/openimsdk/open-im-server/v3/version" "github.com/openimsdk/tools/utils/datautil" @@ -37,6 +38,14 @@ func Build() { if len(bin) != 0 { bin = bin[1:] } + + mageutil.WithSpinner("Generating protocol artifacts...", func() { + if err := sh.Run("mage", "-d", "protocol", "GenGo"); err != nil { + mageutil.PrintRed("protocol compilation failed: " + err.Error()) + os.Exit(1) + } + }) + mageutil.WithSpinner("Building binaries...", func() { mageutil.Build(bin, nil, nil) }) } @@ -54,11 +63,28 @@ func BuildWithCustomConfig() { ToolsDir: &customToolsDir, } + mageutil.WithSpinner("Generating protocol artifacts...", func() { + if err := sh.Run("mage", "-d", "protocol", "GenGo"); err != nil { + mageutil.PrintRed("protocol compilation failed: " + err.Error()) + os.Exit(1) + } + }) + mageutil.WithSpinner("Building binaries with custom config...", func() { mageutil.Build(bin, config, nil) }) } +// Protocol generates protobuf artifacts under `./protocol`. +func Protocol() { + mageutil.WithSpinner("Generating protocol artifacts...", func() { + if err := sh.Run("mage", "-d", "protocol", "GenGo"); err != nil { + mageutil.PrintRed("protocol compilation failed: " + err.Error()) + os.Exit(1) + } + }) +} + func Start() { mageutil.InitForSSC() err := setMaxOpenFiles() diff --git a/pkg/common/cmd/constant.go b/pkg/common/cmd/constant.go index 45dbcafda..e76219ed4 100644 --- a/pkg/common/cmd/constant.go +++ b/pkg/common/cmd/constant.go @@ -34,7 +34,9 @@ var ( OpenIMMsgGatewayCfgFileName string OpenIMMsgTransferCfgFileName string OpenIMPushCfgFileName string + OpenIMCaptchaCfgFileName string OpenIMRPCAuthCfgFileName string + OpenIMRPCCaptchaCfgFileName string OpenIMRPCConversationCfgFileName string OpenIMRPCFriendCfgFileName string OpenIMRPCGroupCfgFileName string @@ -62,7 +64,9 @@ func init() { OpenIMMsgGatewayCfgFileName = "openim-msggateway.yml" OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml" OpenIMPushCfgFileName = "openim-push.yml" + OpenIMCaptchaCfgFileName = "openim-captcha.yml" OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml" + OpenIMRPCCaptchaCfgFileName = "openim-rpc-captcha.yml" OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml" OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml" OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml" @@ -77,7 +81,7 @@ func init() { KafkaConfigFileName, RedisConfigFileName, MongodbConfigFileName, MinioConfigFileName, LogConfigFileName, OpenIMAPICfgFileName, OpenIMCronTaskCfgFileName, OpenIMMsgGatewayCfgFileName, - OpenIMMsgTransferCfgFileName, OpenIMPushCfgFileName, OpenIMRPCAuthCfgFileName, + OpenIMMsgTransferCfgFileName, OpenIMPushCfgFileName, OpenIMCaptchaCfgFileName, OpenIMRPCAuthCfgFileName, OpenIMRPCCaptchaCfgFileName, OpenIMRPCConversationCfgFileName, OpenIMRPCFriendCfgFileName, OpenIMRPCGroupCfgFileName, OpenIMRPCMsgCfgFileName, OpenIMRPCThirdCfgFileName, OpenIMRPCUserCfgFileName, DiscoveryConfigFilename, } diff --git a/pkg/common/cmd/rpc_captcha.go b/pkg/common/cmd/rpc_captcha.go new file mode 100644 index 000000000..0d3042eca --- /dev/null +++ b/pkg/common/cmd/rpc_captcha.go @@ -0,0 +1,47 @@ +package cmd + +import ( + "context" + + "github.com/openimsdk/open-im-server/v3/internal/rpc/captcha" + "github.com/openimsdk/open-im-server/v3/pkg/common/startrpc" + "github.com/openimsdk/open-im-server/v3/version" + "github.com/openimsdk/tools/system/program" + "github.com/spf13/cobra" +) + +type CaptchaRpcCmd struct { + *RootCmd + ctx context.Context + configMap map[string]any + captchaConfig *captcha.Config +} + +func NewCaptchaRpcCmd() *CaptchaRpcCmd { + var captchaConfig captcha.Config + ret := &CaptchaRpcCmd{captchaConfig: &captchaConfig} + ret.configMap = map[string]any{ + OpenIMRPCCaptchaCfgFileName: &captchaConfig.RpcConfig, + MongodbConfigFileName: &captchaConfig.MongodbConfig, + ShareFileName: &captchaConfig.Share, + DiscoveryConfigFilename: &captchaConfig.Discovery, + } + ret.RootCmd = NewRootCmd(program.GetProcessName(), WithConfigMap(ret.configMap)) + ret.ctx = context.WithValue(context.Background(), "version", version.Version) + ret.Command.RunE = func(cmd *cobra.Command, args []string) error { + return ret.runE() + } + return ret +} + +func (c *CaptchaRpcCmd) Exec() error { + return c.Execute() +} + +func (c *CaptchaRpcCmd) runE() error { + return startrpc.Start(c.ctx, &c.captchaConfig.Discovery, &c.captchaConfig.RpcConfig.Prometheus, c.captchaConfig.RpcConfig.RPC.ListenIP, + c.captchaConfig.RpcConfig.RPC.RegisterIP, c.captchaConfig.RpcConfig.RPC.AutoSetPorts, c.captchaConfig.RpcConfig.RPC.Ports, + c.Index(), c.captchaConfig.Share.RpcRegisterName.Captcha, &c.captchaConfig.Share, c.captchaConfig, + nil, + captcha.Start) +} diff --git a/pkg/common/config/config.go b/pkg/common/config/config.go index 4cd202db4..09be3987c 100644 --- a/pkg/common/config/config.go +++ b/pkg/common/config/config.go @@ -249,6 +249,18 @@ type Auth struct { } `mapstructure:"tokenPolicy"` } +type Captcha struct { + RPC struct { + RegisterIP string `mapstructure:"registerIP"` + ListenIP string `mapstructure:"listenIP"` + AutoSetPorts bool `mapstructure:"autoSetPorts"` + Ports []int `mapstructure:"ports"` + } `mapstructure:"rpc"` + Prometheus Prometheus `mapstructure:"prometheus"` + VerifyPadding int `mapstructure:"verifyPadding"` + ExpireSeconds int `mapstructure:"expireSeconds"` +} + type Conversation struct { RPC struct { RegisterIP string `mapstructure:"registerIP"` @@ -407,6 +419,7 @@ type RpcRegisterName struct { Auth string `mapstructure:"auth"` Conversation string `mapstructure:"conversation"` Third string `mapstructure:"third"` + Captcha string `mapstructure:"captcha"` } func (r *RpcRegisterName) GetServiceNames() []string { @@ -420,6 +433,7 @@ func (r *RpcRegisterName) GetServiceNames() []string { r.Auth, r.Conversation, r.Third, + r.Captcha, } } @@ -625,6 +639,7 @@ var ( OpenIMMsgTransferCfgFileName = "openim-msgtransfer.yml" OpenIMPushCfgFileName = "openim-push.yml" OpenIMRPCAuthCfgFileName = "openim-rpc-auth.yml" + OpenIMRPCCaptchaCfgFileName = "openim-rpc-captcha.yml" OpenIMRPCConversationCfgFileName = "openim-rpc-conversation.yml" OpenIMRPCFriendCfgFileName = "openim-rpc-friend.yml" OpenIMRPCGroupCfgFileName = "openim-rpc-group.yml" @@ -688,6 +703,10 @@ func (a *Auth) GetConfigFileName() string { return OpenIMRPCAuthCfgFileName } +func (c *Captcha) GetConfigFileName() string { + return OpenIMRPCCaptchaCfgFileName +} + func (c *Conversation) GetConfigFileName() string { return OpenIMRPCConversationCfgFileName } diff --git a/start-config.yml b/start-config.yml index 1231b5d0d..66051f962 100644 --- a/start-config.yml +++ b/start-config.yml @@ -7,6 +7,7 @@ serviceBinaries: openim-msgtransfer: 8 openim-rpc-conversation: 1 openim-rpc-auth: 1 + openim-rpc-captcha: 1 openim-rpc-group: 1 openim-rpc-friend: 1 openim-rpc-msg: 1