commit
3d95f70689
@ -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.NewCryptoRpcCmd().Exec(); err != nil {
|
||||
program.ExitWithError(err)
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
rpc:
|
||||
registerIP: ''
|
||||
listenIP: 0.0.0.0
|
||||
autoSetPorts: true
|
||||
ports:
|
||||
- 10190
|
||||
prometheus:
|
||||
enable: true
|
||||
ports:
|
||||
- 20190
|
||||
virgil:
|
||||
appID: ''
|
||||
appKey: ''
|
||||
appKeyID: ''
|
||||
@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/openimsdk/protocol/crypto"
|
||||
"github.com/openimsdk/tools/a2r"
|
||||
)
|
||||
|
||||
type CryptoApi struct {
|
||||
Client crypto.CryptoServiceClient
|
||||
}
|
||||
|
||||
func NewCryptoApi(client crypto.CryptoServiceClient) CryptoApi {
|
||||
return CryptoApi{Client: client}
|
||||
}
|
||||
|
||||
func (o *CryptoApi) RegisterDevice(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.RegisterDevice, o.Client)
|
||||
}
|
||||
|
||||
func (o *CryptoApi) GetDevices(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.GetDevices, o.Client)
|
||||
}
|
||||
|
||||
func (o *CryptoApi) RevokeDevice(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.RevokeDevice, o.Client)
|
||||
}
|
||||
|
||||
func (o *CryptoApi) GetVirgilJWT(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.GetVirgilJWT, o.Client)
|
||||
}
|
||||
|
||||
func (o *CryptoApi) GetGroupKeyVersion(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.GetGroupKeyVersion, o.Client)
|
||||
}
|
||||
|
||||
func (o *CryptoApi) GetGroupKeyEvents(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.GetGroupKeyEvents, o.Client)
|
||||
}
|
||||
|
||||
func (o *CryptoApi) SecurityPrecheck(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.SecurityPrecheck, o.Client)
|
||||
}
|
||||
|
||||
func (o *CryptoApi) IntegrityReport(c *gin.Context) {
|
||||
a2r.Call(c, crypto.CryptoServiceClient.IntegrityReport, o.Client)
|
||||
}
|
||||
@ -0,0 +1,496 @@
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/VirgilSecurity/virgil-sdk-go/cryptoimpl"
|
||||
"github.com/VirgilSecurity/virgil-sdk-go/sdk"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/authverify"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/config"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/controller"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database/mgo"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||
pbcrypto "github.com/openimsdk/protocol/crypto"
|
||||
"github.com/openimsdk/tools/db/mongoutil"
|
||||
"github.com/openimsdk/tools/discovery"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"github.com/openimsdk/tools/mcontext"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const virgilJWTTTL = 20 * time.Minute
|
||||
|
||||
type Config struct {
|
||||
RpcConfig config.Crypto
|
||||
MongodbConfig config.Mongo
|
||||
Share config.Share
|
||||
Discovery config.Discovery
|
||||
}
|
||||
|
||||
type cryptoServer struct {
|
||||
pbcrypto.UnimplementedCryptoServiceServer
|
||||
config *Config
|
||||
cryptoDB controller.CryptoDatabase
|
||||
jwtGenerator *sdk.JwtGenerator
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, config *Config, _ discovery.SvcDiscoveryRegistry, server *grpc.Server) error {
|
||||
mgocli, err := mongoutil.NewMongoDB(ctx, config.MongodbConfig.Build())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
db := mgocli.GetDB()
|
||||
|
||||
deviceDB, err := mgo.NewCryptoDeviceMongo(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyVersionDB, err := mgo.NewGroupKeyVersionMongo(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyEventDB, err := mgo.NewGroupKeyEventMongo(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cryptoDB := controller.NewCryptoDatabase(deviceDB, keyVersionDB, keyEventDB, mgocli.GetTx())
|
||||
|
||||
var jwtGen *sdk.JwtGenerator
|
||||
vc := config.RpcConfig.Virgil
|
||||
if vc.AppID != "" && vc.AppKey != "" && vc.AppKeyID != "" {
|
||||
virgilCrypto := cryptoimpl.NewVirgilCrypto()
|
||||
privateKey, err := virgilCrypto.ImportPrivateKey([]byte(vc.AppKey), "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("import virgil app key: %w", err)
|
||||
}
|
||||
jwtGen = sdk.NewJwtGenerator(
|
||||
privateKey,
|
||||
vc.AppKeyID,
|
||||
cryptoimpl.NewVirgilAccessTokenSigner(),
|
||||
vc.AppID,
|
||||
virgilJWTTTL,
|
||||
)
|
||||
}
|
||||
|
||||
pbcrypto.RegisterCryptoServiceServer(server, &cryptoServer{
|
||||
config: config,
|
||||
cryptoDB: cryptoDB,
|
||||
jwtGenerator: jwtGen,
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *cryptoServer) RegisterDevice(ctx context.Context, req *pbcrypto.RegisterDeviceReq) (*pbcrypto.RegisterDeviceResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "RegisterDevice request",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"platform", req.Platform,
|
||||
"deviceModel", req.DeviceModel,
|
||||
"appVersion", req.AppVersion,
|
||||
)
|
||||
if req.UserID == "" || req.DeviceID == "" {
|
||||
log.ZError(ctx, "RegisterDevice invalid args", errs.ErrArgs,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, errs.ErrArgs.WrapMsg("userID and deviceID are required")
|
||||
}
|
||||
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
|
||||
log.ZError(ctx, "RegisterDevice auth check failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
device, err := s.cryptoDB.RegisterDevice(ctx, req.UserID, req.DeviceID, req.Platform, req.DeviceModel, req.AppVersion)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "RegisterDevice db failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"platform", req.Platform,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
log.ZDebug(ctx, "RegisterDevice success",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"virgilIdentity", device.VirgilIdentity,
|
||||
)
|
||||
return &pbcrypto.RegisterDeviceResp{
|
||||
Device: modelDeviceToProto(device),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *cryptoServer) GetDevices(ctx context.Context, req *pbcrypto.GetDevicesReq) (*pbcrypto.GetDevicesResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "GetDevices request", "opUserID", opUserID, "targetUserID", req.UserID)
|
||||
if req.UserID == "" {
|
||||
log.ZError(ctx, "GetDevices invalid args", errs.ErrArgs, "opUserID", opUserID, "targetUserID", req.UserID)
|
||||
return nil, errs.ErrArgs.WrapMsg("userID is required")
|
||||
}
|
||||
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
|
||||
log.ZError(ctx, "GetDevices auth check failed", err, "opUserID", opUserID, "targetUserID", req.UserID)
|
||||
return nil, err
|
||||
}
|
||||
devices, err := s.cryptoDB.GetDevices(ctx, req.UserID)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "GetDevices db failed", err, "opUserID", opUserID, "targetUserID", req.UserID)
|
||||
return nil, err
|
||||
}
|
||||
pbDevices := make([]*pbcrypto.DeviceInfo, 0, len(devices))
|
||||
for _, d := range devices {
|
||||
pbDevices = append(pbDevices, modelDeviceToProto(d))
|
||||
}
|
||||
log.ZDebug(ctx, "GetDevices success",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceCount", len(devices),
|
||||
)
|
||||
return &pbcrypto.GetDevicesResp{Devices: pbDevices}, nil
|
||||
}
|
||||
|
||||
func (s *cryptoServer) RevokeDevice(ctx context.Context, req *pbcrypto.RevokeDeviceReq) (*pbcrypto.RevokeDeviceResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "RevokeDevice request",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
if req.UserID == "" || req.DeviceID == "" {
|
||||
log.ZError(ctx, "RevokeDevice invalid args", errs.ErrArgs,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, errs.ErrArgs.WrapMsg("userID and deviceID are required")
|
||||
}
|
||||
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
|
||||
log.ZError(ctx, "RevokeDevice auth check failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
if err := s.cryptoDB.RevokeDevice(ctx, req.UserID, req.DeviceID); err != nil {
|
||||
log.ZError(ctx, "RevokeDevice db failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
log.ZDebug(ctx, "RevokeDevice success",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return &pbcrypto.RevokeDeviceResp{}, nil
|
||||
}
|
||||
|
||||
func (s *cryptoServer) GetVirgilJWT(ctx context.Context, req *pbcrypto.GetVirgilJWTReq) (*pbcrypto.GetVirgilJWTResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "GetVirgilJWT request",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
if req.UserID == "" || req.DeviceID == "" {
|
||||
log.ZError(ctx, "GetVirgilJWT invalid args", errs.ErrArgs,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, errs.ErrArgs.WrapMsg("userID and deviceID are required")
|
||||
}
|
||||
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
|
||||
log.ZError(ctx, "GetVirgilJWT auth check failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
if s.jwtGenerator == nil {
|
||||
log.ZError(ctx, "GetVirgilJWT jwt generator not configured", errs.New("virgil is not configured"),
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, errs.New("virgil is not configured").Wrap()
|
||||
}
|
||||
|
||||
device, err := s.cryptoDB.GetDevice(ctx, req.UserID, req.DeviceID)
|
||||
if err != nil {
|
||||
if errs.ErrRecordNotFound.Is(err) {
|
||||
log.ZError(ctx, "GetVirgilJWT device not found", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, errs.ErrRecordNotFound.WrapMsg("device not found")
|
||||
}
|
||||
log.ZError(ctx, "GetVirgilJWT query device failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
if device.Status != "active" {
|
||||
log.ZError(ctx, "GetVirgilJWT device revoked", errs.ErrNoPermission,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"status", device.Status,
|
||||
)
|
||||
return nil, errs.ErrNoPermission.WrapMsg("device is revoked")
|
||||
}
|
||||
|
||||
if err := s.cryptoDB.TouchDevice(ctx, req.UserID, req.DeviceID); err != nil {
|
||||
log.ZError(ctx, "TouchDevice failed", err,
|
||||
"opUserID", opUserID,
|
||||
"userID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
}
|
||||
|
||||
identity := req.UserID + ":" + req.DeviceID
|
||||
token, err := s.jwtGenerator.GenerateToken(identity, nil)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "GetVirgilJWT generate token failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"virgilIdentity", identity,
|
||||
)
|
||||
return nil, errs.New("generate virgil jwt failed").Wrap()
|
||||
}
|
||||
log.ZDebug(ctx, "GetVirgilJWT success",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"virgilIdentity", identity,
|
||||
"expiresInSec", int64(virgilJWTTTL/time.Second),
|
||||
)
|
||||
|
||||
return &pbcrypto.GetVirgilJWTResp{
|
||||
VirgilJWT: token.String(),
|
||||
ExpiresIn: int64(virgilJWTTTL / time.Second),
|
||||
VirgilIdentity: identity,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *cryptoServer) GetGroupKeyVersion(ctx context.Context, req *pbcrypto.GetGroupKeyVersionReq) (*pbcrypto.GetGroupKeyVersionResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "GetGroupKeyVersion request", "opUserID", opUserID, "groupID", req.GroupID)
|
||||
if req.GroupID == "" {
|
||||
log.ZError(ctx, "GetGroupKeyVersion invalid args", errs.ErrArgs, "opUserID", opUserID, "groupID", req.GroupID)
|
||||
return nil, errs.ErrArgs.WrapMsg("groupID is required")
|
||||
}
|
||||
version, err := s.cryptoDB.GetGroupKeyVersion(ctx, req.GroupID)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "GetGroupKeyVersion db failed", err, "opUserID", opUserID, "groupID", req.GroupID)
|
||||
return nil, err
|
||||
}
|
||||
log.ZDebug(ctx, "GetGroupKeyVersion success",
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"groupKeyVersion", version,
|
||||
)
|
||||
return &pbcrypto.GetGroupKeyVersionResp{
|
||||
GroupID: req.GroupID,
|
||||
GroupKeyVersion: version,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BumpGroupKeyVersion is internal-only (not exposed via HTTP API).
|
||||
// Called by Group Service after membership changes.
|
||||
func (s *cryptoServer) BumpGroupKeyVersion(ctx context.Context, req *pbcrypto.BumpGroupKeyVersionReq) (*pbcrypto.BumpGroupKeyVersionResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "BumpGroupKeyVersion request",
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"operatorUserID", req.OperatorUserID,
|
||||
"eventType", req.EventType,
|
||||
)
|
||||
if req.GroupID == "" {
|
||||
log.ZError(ctx, "BumpGroupKeyVersion invalid args", errs.ErrArgs,
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"operatorUserID", req.OperatorUserID,
|
||||
"eventType", req.EventType,
|
||||
)
|
||||
return nil, errs.ErrArgs.WrapMsg("groupID is required")
|
||||
}
|
||||
newVersion, err := s.cryptoDB.BumpGroupKeyVersion(ctx, req.GroupID, req.OperatorUserID, req.EventType)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "BumpGroupKeyVersion db failed", err,
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"operatorUserID", req.OperatorUserID,
|
||||
"eventType", req.EventType,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
log.ZDebug(ctx, "BumpGroupKeyVersion success",
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"operatorUserID", req.OperatorUserID,
|
||||
"eventType", req.EventType,
|
||||
"newGroupKeyVersion", newVersion,
|
||||
)
|
||||
return &pbcrypto.BumpGroupKeyVersionResp{
|
||||
GroupID: req.GroupID,
|
||||
GroupKeyVersion: newVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *cryptoServer) GetGroupKeyEvents(ctx context.Context, req *pbcrypto.GetGroupKeyEventsReq) (*pbcrypto.GetGroupKeyEventsResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "GetGroupKeyEvents request",
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"sinceVersion", req.SinceVersion,
|
||||
)
|
||||
if req.GroupID == "" {
|
||||
log.ZError(ctx, "GetGroupKeyEvents invalid args", errs.ErrArgs,
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"sinceVersion", req.SinceVersion,
|
||||
)
|
||||
return nil, errs.ErrArgs.WrapMsg("groupID is required")
|
||||
}
|
||||
events, err := s.cryptoDB.GetGroupKeyEvents(ctx, req.GroupID, req.SinceVersion)
|
||||
if err != nil {
|
||||
log.ZError(ctx, "GetGroupKeyEvents db failed", err,
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"sinceVersion", req.SinceVersion,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
pbEvents := make([]*pbcrypto.GroupKeyEventInfo, 0, len(events))
|
||||
for _, e := range events {
|
||||
pbEvents = append(pbEvents, &pbcrypto.GroupKeyEventInfo{
|
||||
EventID: e.EventID,
|
||||
GroupID: e.GroupID,
|
||||
GroupKeyVersion: e.GroupKeyVersion,
|
||||
EventType: e.EventType,
|
||||
OperatorUserID: e.OperatorUserID,
|
||||
CreateTime: e.CreateTime.UnixMilli(),
|
||||
})
|
||||
}
|
||||
log.ZDebug(ctx, "GetGroupKeyEvents success",
|
||||
"opUserID", opUserID,
|
||||
"groupID", req.GroupID,
|
||||
"sinceVersion", req.SinceVersion,
|
||||
"eventCount", len(events),
|
||||
)
|
||||
return &pbcrypto.GetGroupKeyEventsResp{Events: pbEvents}, nil
|
||||
}
|
||||
|
||||
func (s *cryptoServer) SecurityPrecheck(ctx context.Context, req *pbcrypto.SecurityPrecheckReq) (*pbcrypto.SecurityPrecheckResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "SecurityPrecheck request",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"action", req.Action,
|
||||
)
|
||||
if req.UserID == "" || req.DeviceID == "" {
|
||||
log.ZError(ctx, "SecurityPrecheck invalid args", errs.ErrArgs,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"action", req.Action,
|
||||
)
|
||||
return nil, errs.ErrArgs.WrapMsg("userID and deviceID are required")
|
||||
}
|
||||
if err := authverify.CheckAccessV3(ctx, req.UserID, s.config.Share.IMAdminUserID); err != nil {
|
||||
log.ZError(ctx, "SecurityPrecheck auth check failed", err,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"action", req.Action,
|
||||
)
|
||||
return nil, err
|
||||
}
|
||||
device, err := s.cryptoDB.GetDevice(ctx, req.UserID, req.DeviceID)
|
||||
if err != nil {
|
||||
log.ZDebug(ctx, "SecurityPrecheck denied",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"reason", "device not found",
|
||||
)
|
||||
return &pbcrypto.SecurityPrecheckResp{Allowed: false, Reason: "device not found"}, nil
|
||||
}
|
||||
if device.Status != "active" {
|
||||
log.ZDebug(ctx, "SecurityPrecheck denied",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"reason", "device is revoked",
|
||||
)
|
||||
return &pbcrypto.SecurityPrecheckResp{Allowed: false, Reason: "device is revoked"}, nil
|
||||
}
|
||||
log.ZDebug(ctx, "SecurityPrecheck allowed",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return &pbcrypto.SecurityPrecheckResp{Allowed: true}, nil
|
||||
}
|
||||
|
||||
// IntegrityReport is a placeholder for future device integrity verification.
|
||||
// Currently accepts all reports; implement validation logic when ready.
|
||||
func (s *cryptoServer) IntegrityReport(ctx context.Context, req *pbcrypto.IntegrityReportReq) (*pbcrypto.IntegrityReportResp, error) {
|
||||
opUserID := mcontext.GetOpUserID(ctx)
|
||||
log.ZDebug(ctx, "IntegrityReport request",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"timestamp", req.Timestamp,
|
||||
"reportSize", len(req.ReportData),
|
||||
)
|
||||
if req.UserID == "" || req.DeviceID == "" {
|
||||
log.ZError(ctx, "IntegrityReport invalid args", errs.ErrArgs,
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
"timestamp", req.Timestamp,
|
||||
)
|
||||
return nil, errs.ErrArgs.WrapMsg("userID and deviceID are required")
|
||||
}
|
||||
log.ZDebug(ctx, "IntegrityReport accepted",
|
||||
"opUserID", opUserID,
|
||||
"targetUserID", req.UserID,
|
||||
"deviceID", req.DeviceID,
|
||||
)
|
||||
return &pbcrypto.IntegrityReportResp{Accepted: true}, nil
|
||||
}
|
||||
|
||||
func modelDeviceToProto(d *model.CryptoDevice) *pbcrypto.DeviceInfo {
|
||||
return &pbcrypto.DeviceInfo{
|
||||
DeviceID: d.DeviceID,
|
||||
UserID: d.UserID,
|
||||
Platform: d.Platform,
|
||||
DeviceModel: d.DeviceModel,
|
||||
AppVersion: d.AppVersion,
|
||||
VirgilIdentity: d.VirgilIdentity,
|
||||
Status: d.Status,
|
||||
LastSeenAt: d.LastSeenAt.UnixMilli(),
|
||||
CreateTime: d.CreateTime.UnixMilli(),
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/internal/rpc/crypto"
|
||||
"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 CryptoRpcCmd struct {
|
||||
*RootCmd
|
||||
ctx context.Context
|
||||
configMap map[string]any
|
||||
cryptoConfig *crypto.Config
|
||||
}
|
||||
|
||||
func NewCryptoRpcCmd() *CryptoRpcCmd {
|
||||
var cryptoConfig crypto.Config
|
||||
ret := &CryptoRpcCmd{cryptoConfig: &cryptoConfig}
|
||||
ret.configMap = map[string]any{
|
||||
OpenIMRPCCryptoCfgFileName: &cryptoConfig.RpcConfig,
|
||||
MongodbConfigFileName: &cryptoConfig.MongodbConfig,
|
||||
ShareFileName: &cryptoConfig.Share,
|
||||
DiscoveryConfigFilename: &cryptoConfig.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 *CryptoRpcCmd) Exec() error {
|
||||
return c.Execute()
|
||||
}
|
||||
|
||||
func (c *CryptoRpcCmd) runE() error {
|
||||
return startrpc.Start(c.ctx, &c.cryptoConfig.Discovery, &c.cryptoConfig.RpcConfig.Prometheus, c.cryptoConfig.RpcConfig.RPC.ListenIP,
|
||||
c.cryptoConfig.RpcConfig.RPC.RegisterIP, c.cryptoConfig.RpcConfig.RPC.AutoSetPorts, c.cryptoConfig.RpcConfig.RPC.Ports,
|
||||
c.Index(), c.cryptoConfig.Share.RpcRegisterName.Crypto, &c.cryptoConfig.Share, c.cryptoConfig,
|
||||
nil,
|
||||
crypto.Start)
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||
"github.com/openimsdk/tools/db/tx"
|
||||
"github.com/openimsdk/tools/log"
|
||||
)
|
||||
|
||||
type CryptoDatabase interface {
|
||||
RegisterDevice(ctx context.Context, userID, deviceID, platform, deviceModel, appVersion string) (*model.CryptoDevice, error)
|
||||
GetDevices(ctx context.Context, userID string) ([]*model.CryptoDevice, error)
|
||||
GetDevice(ctx context.Context, userID, deviceID string) (*model.CryptoDevice, error)
|
||||
RevokeDevice(ctx context.Context, userID, deviceID string) error
|
||||
TouchDevice(ctx context.Context, userID, deviceID string) error
|
||||
|
||||
GetGroupKeyVersion(ctx context.Context, groupID string) (int64, error)
|
||||
BumpGroupKeyVersion(ctx context.Context, groupID, operatorUserID, eventType string) (int64, error)
|
||||
GetGroupKeyEvents(ctx context.Context, groupID string, sinceVersion int64) ([]*model.GroupKeyEvent, error)
|
||||
}
|
||||
|
||||
type cryptoDatabase struct {
|
||||
deviceDB database.CryptoDevice
|
||||
keyVersionDB database.GroupKeyVersion
|
||||
keyEventDB database.GroupKeyEvent
|
||||
tx tx.Tx
|
||||
}
|
||||
|
||||
func NewCryptoDatabase(
|
||||
deviceDB database.CryptoDevice,
|
||||
keyVersionDB database.GroupKeyVersion,
|
||||
keyEventDB database.GroupKeyEvent,
|
||||
tx tx.Tx,
|
||||
) CryptoDatabase {
|
||||
return &cryptoDatabase{
|
||||
deviceDB: deviceDB,
|
||||
keyVersionDB: keyVersionDB,
|
||||
keyEventDB: keyEventDB,
|
||||
tx: tx,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) RegisterDevice(ctx context.Context, userID, deviceID, platform, deviceModel, appVersion string) (*model.CryptoDevice, error) {
|
||||
virgilIdentity := userID + ":" + deviceID
|
||||
now := time.Now()
|
||||
device := &model.CryptoDevice{
|
||||
DeviceID: deviceID,
|
||||
UserID: userID,
|
||||
Platform: platform,
|
||||
DeviceModel: deviceModel,
|
||||
AppVersion: appVersion,
|
||||
VirgilIdentity: virgilIdentity,
|
||||
Status: "active",
|
||||
LastSeenAt: now,
|
||||
CreateTime: now,
|
||||
}
|
||||
if err := c.deviceDB.Create(ctx, device); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return device, nil
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) GetDevices(ctx context.Context, userID string) ([]*model.CryptoDevice, error) {
|
||||
return c.deviceDB.FindByUserID(ctx, userID)
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) GetDevice(ctx context.Context, userID, deviceID string) (*model.CryptoDevice, error) {
|
||||
return c.deviceDB.FindByUserIDAndDeviceID(ctx, userID, deviceID)
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) RevokeDevice(ctx context.Context, userID, deviceID string) error {
|
||||
return c.deviceDB.UpdateStatus(ctx, userID, deviceID, "revoked")
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) TouchDevice(ctx context.Context, userID, deviceID string) error {
|
||||
return c.deviceDB.UpdateLastSeen(ctx, userID, deviceID)
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) GetGroupKeyVersion(ctx context.Context, groupID string) (int64, error) {
|
||||
v, err := c.keyVersionDB.Find(ctx, groupID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return v.GroupKeyVersion, nil
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) BumpGroupKeyVersion(ctx context.Context, groupID, operatorUserID, eventType string) (int64, error) {
|
||||
log.ZDebug(ctx, "cryptoDatabase BumpGroupKeyVersion begin",
|
||||
"groupID", groupID,
|
||||
"operatorUserID", operatorUserID,
|
||||
"eventType", eventType,
|
||||
)
|
||||
var newVersion int64
|
||||
err := c.tx.Transaction(ctx, func(ctx context.Context) error {
|
||||
var err error
|
||||
newVersion, err = c.keyVersionDB.IncrVersion(ctx, groupID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
event := &model.GroupKeyEvent{
|
||||
EventID: uuid.New().String(),
|
||||
GroupID: groupID,
|
||||
GroupKeyVersion: newVersion,
|
||||
EventType: eventType,
|
||||
OperatorUserID: operatorUserID,
|
||||
CreateTime: time.Now(),
|
||||
}
|
||||
return c.keyEventDB.Create(ctx, event)
|
||||
})
|
||||
if err != nil {
|
||||
log.ZError(ctx, "cryptoDatabase BumpGroupKeyVersion failed", err,
|
||||
"groupID", groupID,
|
||||
"operatorUserID", operatorUserID,
|
||||
"eventType", eventType,
|
||||
)
|
||||
return 0, err
|
||||
}
|
||||
log.ZDebug(ctx, "cryptoDatabase BumpGroupKeyVersion success",
|
||||
"groupID", groupID,
|
||||
"operatorUserID", operatorUserID,
|
||||
"eventType", eventType,
|
||||
"newGroupKeyVersion", newVersion,
|
||||
)
|
||||
return newVersion, nil
|
||||
}
|
||||
|
||||
func (c *cryptoDatabase) GetGroupKeyEvents(ctx context.Context, groupID string, sinceVersion int64) ([]*model.GroupKeyEvent, error) {
|
||||
return c.keyEventDB.FindSinceVersion(ctx, groupID, sinceVersion)
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||
)
|
||||
|
||||
type CryptoDevice interface {
|
||||
Create(ctx context.Context, device *model.CryptoDevice) error
|
||||
FindByUserID(ctx context.Context, userID string) ([]*model.CryptoDevice, error)
|
||||
FindByUserIDAndDeviceID(ctx context.Context, userID, deviceID string) (*model.CryptoDevice, error)
|
||||
UpdateStatus(ctx context.Context, userID, deviceID, status string) error
|
||||
UpdateLastSeen(ctx context.Context, userID, deviceID string) error
|
||||
}
|
||||
|
||||
type GroupKeyVersion interface {
|
||||
Find(ctx context.Context, groupID string) (*model.GroupKeyVersion, error)
|
||||
IncrVersion(ctx context.Context, groupID string) (int64, error)
|
||||
}
|
||||
|
||||
type GroupKeyEvent interface {
|
||||
Create(ctx context.Context, event *model.GroupKeyEvent) error
|
||||
FindSinceVersion(ctx context.Context, groupID string, sinceVersion int64) ([]*model.GroupKeyEvent, error)
|
||||
}
|
||||
@ -0,0 +1,183 @@
|
||||
package mgo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/database"
|
||||
"github.com/openimsdk/open-im-server/v3/pkg/common/storage/model"
|
||||
"github.com/openimsdk/tools/errs"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// ---- CryptoDevice ----
|
||||
|
||||
type CryptoDeviceMgo struct {
|
||||
coll *mongo.Collection
|
||||
}
|
||||
|
||||
func NewCryptoDeviceMongo(db *mongo.Database) (database.CryptoDevice, error) {
|
||||
coll := db.Collection("crypto_device")
|
||||
_, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{{Key: "user_id", Value: 1}, {Key: "device_id", Value: 1}},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "user_id", Value: 1}},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &CryptoDeviceMgo{coll: coll}, nil
|
||||
}
|
||||
|
||||
func (m *CryptoDeviceMgo) Create(ctx context.Context, device *model.CryptoDevice) error {
|
||||
_, err := m.coll.InsertOne(ctx, device)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *CryptoDeviceMgo) FindByUserID(ctx context.Context, userID string) ([]*model.CryptoDevice, error) {
|
||||
cursor, err := m.coll.Find(ctx, bson.M{"user_id": userID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var devices []*model.CryptoDevice
|
||||
if err := cursor.All(ctx, &devices); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return devices, nil
|
||||
}
|
||||
|
||||
func (m *CryptoDeviceMgo) FindByUserIDAndDeviceID(ctx context.Context, userID, deviceID string) (*model.CryptoDevice, error) {
|
||||
var device model.CryptoDevice
|
||||
err := m.coll.FindOne(ctx, bson.M{"user_id": userID, "device_id": deviceID}).Decode(&device)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, errs.ErrRecordNotFound.WrapMsg("crypto device not found", "userID", userID, "deviceID", deviceID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &device, nil
|
||||
}
|
||||
|
||||
func (m *CryptoDeviceMgo) UpdateStatus(ctx context.Context, userID, deviceID, status string) error {
|
||||
result, err := m.coll.UpdateOne(ctx,
|
||||
bson.M{"user_id": userID, "device_id": deviceID},
|
||||
bson.M{"$set": bson.M{"status": status}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.MatchedCount == 0 {
|
||||
return errs.ErrRecordNotFound.WrapMsg("crypto device not found", "userID", userID, "deviceID", deviceID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CryptoDeviceMgo) UpdateLastSeen(ctx context.Context, userID, deviceID string) error {
|
||||
result, err := m.coll.UpdateOne(ctx,
|
||||
bson.M{"user_id": userID, "device_id": deviceID},
|
||||
bson.M{"$set": bson.M{"last_seen_at": time.Now()}},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if result.MatchedCount == 0 {
|
||||
return errs.ErrRecordNotFound.WrapMsg("crypto device not found", "userID", userID, "deviceID", deviceID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ---- GroupKeyVersion ----
|
||||
|
||||
type GroupKeyVersionMgo struct {
|
||||
coll *mongo.Collection
|
||||
}
|
||||
|
||||
func NewGroupKeyVersionMongo(db *mongo.Database) (database.GroupKeyVersion, error) {
|
||||
coll := db.Collection("group_key_version")
|
||||
_, err := coll.Indexes().CreateOne(context.Background(), mongo.IndexModel{
|
||||
Keys: bson.D{{Key: "group_id", Value: 1}},
|
||||
Options: options.Index().SetUnique(true),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &GroupKeyVersionMgo{coll: coll}, nil
|
||||
}
|
||||
|
||||
func (m *GroupKeyVersionMgo) Find(ctx context.Context, groupID string) (*model.GroupKeyVersion, error) {
|
||||
var v model.GroupKeyVersion
|
||||
err := m.coll.FindOne(ctx, bson.M{"group_id": groupID}).Decode(&v)
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, errs.ErrRecordNotFound.WrapMsg("group key version not found", "groupID", groupID)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &v, nil
|
||||
}
|
||||
|
||||
func (m *GroupKeyVersionMgo) IncrVersion(ctx context.Context, groupID string) (int64, error) {
|
||||
var result model.GroupKeyVersion
|
||||
err := m.coll.FindOneAndUpdate(ctx,
|
||||
bson.M{"group_id": groupID},
|
||||
bson.M{"$inc": bson.M{"group_key_version": int64(1)}},
|
||||
options.FindOneAndUpdate().SetUpsert(true).SetReturnDocument(options.After),
|
||||
).Decode(&result)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.GroupKeyVersion, nil
|
||||
}
|
||||
|
||||
// ---- GroupKeyEvent ----
|
||||
|
||||
type GroupKeyEventMgo struct {
|
||||
coll *mongo.Collection
|
||||
}
|
||||
|
||||
const maxGroupKeyEventsPerQuery = 500
|
||||
|
||||
func NewGroupKeyEventMongo(db *mongo.Database) (database.GroupKeyEvent, error) {
|
||||
coll := db.Collection("group_key_event")
|
||||
_, err := coll.Indexes().CreateMany(context.Background(), []mongo.IndexModel{
|
||||
{
|
||||
Keys: bson.D{{Key: "group_id", Value: 1}, {Key: "group_key_version", Value: 1}},
|
||||
},
|
||||
{
|
||||
Keys: bson.D{{Key: "event_id", Value: 1}},
|
||||
Options: options.Index().SetUnique(true),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &GroupKeyEventMgo{coll: coll}, nil
|
||||
}
|
||||
|
||||
func (m *GroupKeyEventMgo) Create(ctx context.Context, event *model.GroupKeyEvent) error {
|
||||
_, err := m.coll.InsertOne(ctx, event)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *GroupKeyEventMgo) FindSinceVersion(ctx context.Context, groupID string, sinceVersion int64) ([]*model.GroupKeyEvent, error) {
|
||||
cursor, err := m.coll.Find(ctx, bson.M{
|
||||
"group_id": groupID,
|
||||
"group_key_version": bson.M{"$gt": sinceVersion},
|
||||
}, options.Find().
|
||||
SetSort(bson.D{{Key: "group_key_version", Value: 1}}).
|
||||
SetLimit(maxGroupKeyEventsPerQuery))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var events []*model.GroupKeyEvent
|
||||
if err := cursor.All(ctx, &events); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type CryptoDevice struct {
|
||||
DeviceID string `bson:"device_id"`
|
||||
UserID string `bson:"user_id"`
|
||||
Platform string `bson:"platform"`
|
||||
DeviceModel string `bson:"device_model"`
|
||||
AppVersion string `bson:"app_version"`
|
||||
VirgilIdentity string `bson:"virgil_identity"`
|
||||
Status string `bson:"status"`
|
||||
LastSeenAt time.Time `bson:"last_seen_at"`
|
||||
CreateTime time.Time `bson:"create_time"`
|
||||
}
|
||||
|
||||
type GroupKeyVersion struct {
|
||||
GroupID string `bson:"group_id"`
|
||||
GroupKeyVersion int64 `bson:"group_key_version"`
|
||||
}
|
||||
|
||||
type GroupKeyEvent struct {
|
||||
EventID string `bson:"event_id"`
|
||||
GroupID string `bson:"group_id"`
|
||||
GroupKeyVersion int64 `bson:"group_key_version"`
|
||||
EventType string `bson:"event_type"`
|
||||
OperatorUserID string `bson:"operator_user_id"`
|
||||
CreateTime time.Time `bson:"create_time"`
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
package rpcli
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
pbcrypto "github.com/openimsdk/protocol/crypto"
|
||||
"github.com/openimsdk/tools/log"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
func NewCryptoClient(cc grpc.ClientConnInterface) *CryptoClient {
|
||||
return &CryptoClient{pbcrypto.NewCryptoServiceClient(cc)}
|
||||
}
|
||||
|
||||
type CryptoClient struct {
|
||||
pbcrypto.CryptoServiceClient
|
||||
}
|
||||
|
||||
func (x *CryptoClient) BumpGroupKeyVersion(ctx context.Context, groupID, operatorUserID, eventType string) {
|
||||
log.ZDebug(ctx, "BumpGroupKeyVersion start", "groupID", groupID, "operatorUserID", operatorUserID, "eventType", eventType)
|
||||
resp, err := x.CryptoServiceClient.BumpGroupKeyVersion(ctx, &pbcrypto.BumpGroupKeyVersionReq{
|
||||
GroupID: groupID,
|
||||
OperatorUserID: operatorUserID,
|
||||
EventType: eventType,
|
||||
})
|
||||
if err != nil {
|
||||
log.ZError(ctx, "BumpGroupKeyVersion failed", err,
|
||||
"groupID", groupID,
|
||||
"operatorUserID", operatorUserID,
|
||||
"eventType", eventType,
|
||||
)
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "BumpGroupKeyVersion success", "groupID", groupID, "newVersion", resp.GroupKeyVersion)
|
||||
}
|
||||
|
||||
func (x *CryptoClient) InitGroupKeyVersion(ctx context.Context, groupID string) {
|
||||
log.ZDebug(ctx, "InitGroupKeyVersion start", "groupID", groupID, "eventType", "group_created")
|
||||
_, err := x.CryptoServiceClient.BumpGroupKeyVersion(ctx, &pbcrypto.BumpGroupKeyVersionReq{
|
||||
GroupID: groupID,
|
||||
EventType: "group_created",
|
||||
})
|
||||
if err != nil {
|
||||
log.ZError(ctx, "InitGroupKeyVersion failed", err,
|
||||
"groupID", groupID,
|
||||
"eventType", "group_created",
|
||||
)
|
||||
return
|
||||
}
|
||||
log.ZDebug(ctx, "InitGroupKeyVersion success", "groupID", groupID)
|
||||
}
|
||||
Loading…
Reference in new issue