diff --git a/app/main/api/internal/logic/agent/applyforagentlogic.go b/app/main/api/internal/logic/agent/applyforagentlogic.go index 16a2ee4..8fa1c15 100644 --- a/app/main/api/internal/logic/agent/applyforagentlogic.go +++ b/app/main/api/internal/logic/agent/applyforagentlogic.go @@ -153,7 +153,7 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type if transErr != nil { return nil, transErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", userID) } diff --git a/app/main/api/internal/logic/query/queryservicelogic.go b/app/main/api/internal/logic/query/queryservicelogic.go index 4a2f6db..4b00bef 100644 --- a/app/main/api/internal/logic/query/queryservicelogic.go +++ b/app/main/api/internal/logic/query/queryservicelogic.go @@ -7,6 +7,7 @@ import ( "fmt" "time" "tydata-server/app/main/api/internal/service" + "tydata-server/app/main/model" "tydata-server/common/ctxdata" "tydata-server/common/xerr" "tydata-server/pkg/lzkit/crypto" @@ -124,7 +125,7 @@ func (l *QueryServiceLogic) ProcessMarriageLogic(req *types.QueryServiceReq) (*t if cacheDataErr != nil { return nil, cacheDataErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -185,7 +186,7 @@ func (l *QueryServiceLogic) ProcessHomeServiceLogic(req *types.QueryServiceReq) return nil, cacheDataErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -246,7 +247,7 @@ func (l *QueryServiceLogic) ProcessRiskAssessmentLogic(req *types.QueryServiceRe return nil, cacheDataErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -306,7 +307,7 @@ func (l *QueryServiceLogic) ProcessCompanyInfoLogic(req *types.QueryServiceReq) return nil, cacheDataErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -367,7 +368,7 @@ func (l *QueryServiceLogic) ProcessRentalInfoLogic(req *types.QueryServiceReq) ( return nil, cacheDataErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -428,7 +429,7 @@ func (l *QueryServiceLogic) ProcessPreLoanBackgroundCheckLogic(req *types.QueryS return nil, cacheDataErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } @@ -488,7 +489,7 @@ func (l *QueryServiceLogic) ProcessBackgroundCheckLogic(req *types.QueryServiceR return nil, cacheDataErr } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID) } diff --git a/app/main/api/internal/logic/user/bindmobilelogic.go b/app/main/api/internal/logic/user/bindmobilelogic.go index 7096bcf..0ec7852 100644 --- a/app/main/api/internal/logic/user/bindmobilelogic.go +++ b/app/main/api/internal/logic/user/bindmobilelogic.go @@ -78,7 +78,7 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind } } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 生成token失败: %+v", err) } diff --git a/app/main/api/internal/logic/user/detaillogic.go b/app/main/api/internal/logic/user/detaillogic.go index 984567e..b50f478 100644 --- a/app/main/api/internal/logic/user/detaillogic.go +++ b/app/main/api/internal/logic/user/detaillogic.go @@ -37,7 +37,7 @@ func (l *DetailLogic) Detail() (resp *types.UserInfoResp, err error) { userID := claims.UserId userType := claims.UserType - if userType == model.UserTypeTemp { + if userType != model.UserTypeNormal { return &types.UserInfoResp{ UserInfo: types.User{ Id: userID, diff --git a/app/main/api/internal/logic/user/gettokenlogic.go b/app/main/api/internal/logic/user/gettokenlogic.go index a95ebda..437b6c2 100644 --- a/app/main/api/internal/logic/user/gettokenlogic.go +++ b/app/main/api/internal/logic/user/gettokenlogic.go @@ -29,11 +29,11 @@ func NewGetTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetToken } func (l *GetTokenLogic) GetToken() (resp *types.MobileCodeLoginResp, err error) { - userID, err := ctxdata.GetUidFromCtx(l.ctx) + claims, err := ctxdata.GetClaimsFromCtx(l.ctx) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err) } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, claims.UserId, claims.UserType) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err) } diff --git a/app/main/api/internal/logic/user/mobilecodeloginlogic.go b/app/main/api/internal/logic/user/mobilecodeloginlogic.go index d543e33..21525e0 100644 --- a/app/main/api/internal/logic/user/mobilecodeloginlogic.go +++ b/app/main/api/internal/logic/user/mobilecodeloginlogic.go @@ -64,7 +64,7 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r } else { userID = user.Id } - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, model.UserTypeNormal) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", userID) } diff --git a/app/main/api/internal/logic/user/wxh5authlogic.go b/app/main/api/internal/logic/user/wxh5authlogic.go index e51d309..a5b3b57 100644 --- a/app/main/api/internal/logic/user/wxh5authlogic.go +++ b/app/main/api/internal/logic/user/wxh5authlogic.go @@ -47,9 +47,11 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe // Step 3: 处理用户信息 var userID int64 + var userType int64 if userAuth != nil { // 已存在用户,直接登录 userID = userAuth.UserId + userType = model.UserTypeNormal } else { // 检查临时用户表 userTemp, err := l.svcCtx.UserTempModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid) @@ -74,10 +76,11 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe } else { userID = userTemp.Id } + userType = model.UserTypeTemp } // Step 4: 生成JWT Token - token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID) + token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID, userType) if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT token失败: %v", err) } diff --git a/app/main/api/internal/service/userService.go b/app/main/api/internal/service/userService.go index dde6dae..2e54ccf 100644 --- a/app/main/api/internal/service/userService.go +++ b/app/main/api/internal/service/userService.go @@ -77,7 +77,7 @@ func (s *UserService) RegisterUUIDUser(ctx context.Context) (int64, error) { } // generalUserToken 生成用户token -func (s *UserService) GeneralUserToken(ctx context.Context, userID int64) (string, error) { +func (s *UserService) GeneralUserToken(ctx context.Context, userID int64, userType int64) (string, error) { platform, err := ctxdata.GetPlatformFromCtx(ctx) if err != nil { return "", err @@ -85,18 +85,7 @@ func (s *UserService) GeneralUserToken(ctx context.Context, userID int64) (strin var isAgent int64 var agentID int64 - var userType int64 - var user *model.User - users, err := s.userModel.FindAll(ctx, s.userModel.SelectBuilder().Where("id = ?", userID), "") - if err != nil && !errors.Is(err, model.ErrNotFound) { - return "", err - } - if len(users) > 0 { - user = users[0] - } - if user != nil { - userID = user.Id - userType = model.UserTypeNormal + if userType == model.UserTypeNormal { agent, err := s.agentModel.FindOneByUserId(ctx, userID) if err != nil && !errors.Is(err, model.ErrNotFound) { return "", err @@ -112,7 +101,6 @@ func (s *UserService) GeneralUserToken(ctx context.Context, userID int64) (strin } if userTemp != nil { userID = userTemp.Id - userType = model.UserTypeTemp } } token, generaErr := jwtx.GenerateJwtToken(jwtx.JwtClaims{ diff --git a/common/jwt/jwtx_test.go b/common/jwt/jwtx_test.go new file mode 100644 index 0000000..13740f2 --- /dev/null +++ b/common/jwt/jwtx_test.go @@ -0,0 +1,393 @@ +package jwtx + +import ( + "strings" + "testing" + "time" + + "github.com/golang-jwt/jwt/v4" +) + +func TestGenerateJwtToken(t *testing.T) { + // 测试数据 + testClaims := JwtClaims{ + UserId: 1, + AgentId: 0, + Platform: "wxh5", + UserType: 0, + IsAgent: 0, + } + testSecret := "WUvoIwL-FK0qnlxhvxR9tV6SjfOpeJMpKmY2QvT99lA" + testExpire := int64(2592000) // 1小时 + + tests := []struct { + name string + claims JwtClaims + secret string + expire int64 + wantErr bool + }{ + { + name: "正常生成token", + claims: testClaims, + secret: testSecret, + expire: testExpire, + wantErr: false, + }, + { + name: "不同用户数据", + claims: JwtClaims{ + UserId: 99999, + AgentId: 11111, + Platform: "mobile", + UserType: 0, + IsAgent: 1, + }, + secret: testSecret, + expire: testExpire, + wantErr: false, + }, + { + name: "空密钥", + claims: testClaims, + secret: "", + expire: testExpire, + wantErr: false, // 空密钥不会导致生成失败,但验证时会失败 + }, + { + name: "零过期时间", + claims: testClaims, + secret: testSecret, + expire: 0, + wantErr: false, + }, + { + name: "负数过期时间", + claims: testClaims, + secret: testSecret, + expire: -3600, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + token, err := GenerateJwtToken(tt.claims, tt.secret, tt.expire) + + if (err != nil) != tt.wantErr { + t.Errorf("GenerateJwtToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !tt.wantErr { + // 验证token不为空 + if token == "" { + t.Error("GenerateJwtToken() 返回的token为空") + return + } + + // 验证token格式(JWT token应该包含两个点分隔符) + parts := strings.Split(token, ".") + if len(parts) != 3 { + t.Errorf("GenerateJwtToken() 返回的token格式不正确,期望3部分,实际%d部分", len(parts)) + return + } + + // 验证token可以被解析(不验证签名,只验证格式) + parsedToken, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) { + return []byte(tt.secret), nil + }) + + if err == nil && parsedToken != nil { + // 验证claims是否正确设置 + if claims, ok := parsedToken.Claims.(jwt.MapClaims); ok { + // 验证userId + if userId, exists := claims["userId"]; exists { + if int64(userId.(float64)) != tt.claims.UserId { + t.Errorf("token中的userId不匹配,期望%d,实际%v", tt.claims.UserId, userId) + } + } else { + t.Error("token中缺少userId字段") + } + + // 验证extra字段存在 + if _, exists := claims[ExtraKey]; !exists { + t.Error("token中缺少extra字段") + } + + // 验证exp字段 + if exp, exists := claims["exp"]; exists { + expTime := int64(exp.(float64)) + now := time.Now().Unix() + expectedExp := now + tt.expire + // 允许5秒的时间差异 + if expTime < expectedExp-5 || expTime > expectedExp+5 { + t.Errorf("token过期时间不正确,期望约%d,实际%d", expectedExp, expTime) + } + } else { + t.Error("token中缺少exp字段") + } + + // 验证iat字段 + if _, exists := claims["iat"]; !exists { + t.Error("token中缺少iat字段") + } + } + } + + t.Logf("生成的token: %s", token) + } + }) + } +} + +func TestGenerateJwtTokenAndParse(t *testing.T) { + // 测试生成token后能够正确解析 + testClaims := JwtClaims{ + UserId: 12345, + AgentId: 67890, + Platform: "web", + UserType: 1, + IsAgent: 0, + } + testSecret := "test-secret-key" + testExpire := int64(3600) + + // 生成token + token, err := GenerateJwtToken(testClaims, testSecret, testExpire) + if err != nil { + t.Fatalf("GenerateJwtToken() failed: %v", err) + } + + // 解析token + parsedClaims, err := ParseJwtToken(token, testSecret) + if err != nil { + t.Fatalf("ParseJwtToken() failed: %v", err) + } + + // 验证解析出的claims与原始claims一致 + if parsedClaims.UserId != testClaims.UserId { + t.Errorf("UserId不匹配,期望%d,实际%d", testClaims.UserId, parsedClaims.UserId) + } + if parsedClaims.AgentId != testClaims.AgentId { + t.Errorf("AgentId不匹配,期望%d,实际%d", testClaims.AgentId, parsedClaims.AgentId) + } + if parsedClaims.Platform != testClaims.Platform { + t.Errorf("Platform不匹配,期望%s,实际%s", testClaims.Platform, parsedClaims.Platform) + } + if parsedClaims.UserType != testClaims.UserType { + t.Errorf("UserType不匹配,期望%d,实际%d", testClaims.UserType, parsedClaims.UserType) + } + if parsedClaims.IsAgent != testClaims.IsAgent { + t.Errorf("IsAgent不匹配,期望%d,实际%d", testClaims.IsAgent, parsedClaims.IsAgent) + } + + t.Logf("测试通过: 生成token并成功解析,claims数据一致") +} + +func BenchmarkGenerateJwtToken(t *testing.B) { + // 性能测试 + testClaims := JwtClaims{ + UserId: 12345, + AgentId: 67890, + Platform: "web", + UserType: 1, + IsAgent: 0, + } + testSecret := "test-secret-key" + testExpire := int64(3600) + + t.ResetTimer() + for i := 0; i < t.N; i++ { + _, err := GenerateJwtToken(testClaims, testSecret, testExpire) + if err != nil { + t.Fatalf("GenerateJwtToken() failed: %v", err) + } + } +} + +func TestParseJwtToken(t *testing.T) { + // 使用你修改的测试数据 + testClaims := JwtClaims{ + UserId: 6, + AgentId: 0, + Platform: "wxh5", + UserType: 0, + IsAgent: 0, + } + testSecret := "WUvoIwL-FK0qnlxhvxR9tV6SjfOpeJMpKmY2QvT99lA" + testExpire := int64(2592000) // 30天 + + // 先生成一个token用于测试 + token, err := GenerateJwtToken(testClaims, testSecret, testExpire) + if err != nil { + t.Fatalf("生成token失败: %v", err) + } + + t.Logf("生成的测试token: %s", token) + + tests := []struct { + name string + token string + secret string + wantErr bool + wantClaims *JwtClaims + }{ + { + name: "正常解析token", + token: token, + secret: testSecret, + wantErr: false, + wantClaims: &testClaims, + }, + { + name: "错误的密钥", + token: token, + secret: "wrong-secret", + wantErr: true, + wantClaims: nil, + }, + { + name: "空token", + token: "", + secret: testSecret, + wantErr: true, + wantClaims: nil, + }, + { + name: "无效token格式", + token: "invalid.token.format", + secret: testSecret, + wantErr: true, + wantClaims: nil, + }, + { + name: "缺少点分隔符的token", + token: "invalidtoken", + secret: testSecret, + wantErr: true, + wantClaims: nil, + }, + { + name: "自定义token", + token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NTI5MDA5MTQsImV4dHJhIjp7ImFnZW50SWQiOjAsImlzQWdlbnQiOjAsInBsYXRmb3JtIjoid3hoNSIsInVzZXJJZCI6NiwidXNlclR5cGUiOjF9LCJpYXQiOjE3NTAzMDg5MTQsInVzZXJJZCI6Nn0.GPKgLOaALOIa1ft7Hipuo4YKFf5guYt0rz2MCDCSdCQ", + secret: testSecret, + wantErr: false, + wantClaims: &testClaims, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + claims, err := ParseJwtToken(tt.token, tt.secret) + + if (err != nil) != tt.wantErr { + t.Errorf("ParseJwtToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !tt.wantErr && tt.wantClaims != nil { + if claims == nil { + t.Error("ParseJwtToken() 返回的claims为nil") + return + } + + // 验证各个字段 + if claims.UserId != tt.wantClaims.UserId { + t.Errorf("UserId不匹配,期望%d,实际%d", tt.wantClaims.UserId, claims.UserId) + } + if claims.AgentId != tt.wantClaims.AgentId { + t.Errorf("AgentId不匹配,期望%d,实际%d", tt.wantClaims.AgentId, claims.AgentId) + } + if claims.Platform != tt.wantClaims.Platform { + t.Errorf("Platform不匹配,期望%s,实际%s", tt.wantClaims.Platform, claims.Platform) + } + if claims.UserType != tt.wantClaims.UserType { + t.Errorf("UserType不匹配,期望%d,实际%d", tt.wantClaims.UserType, claims.UserType) + } + if claims.IsAgent != tt.wantClaims.IsAgent { + t.Errorf("IsAgent不匹配,期望%d,实际%d", tt.wantClaims.IsAgent, claims.IsAgent) + } + + t.Logf("解析成功的claims: UserId=%d, AgentId=%d, Platform=%s, UserType=%d, IsAgent=%d", + claims.UserId, claims.AgentId, claims.Platform, claims.UserType, claims.IsAgent) + } + }) + } +} + +// TestParseCustomJwtToken 测试解析自定义token - 你可以在这里传入你自己的token +func TestParseCustomJwtToken(t *testing.T) { + // 在这里修改你想要测试的token和secret + customToken := "" // 在这里粘贴你的token + customSecret := "WUvoIwL-FK0qnlxhvxR9tV6SjfOpeJMpKmY2QvT99lA" // 你的密钥 + + // 如果没有提供自定义token,跳过测试 + if customToken == "" { + t.Skip("跳过自定义token测试,请在代码中设置customToken值") + return + } + + t.Logf("解析自定义token: %s", customToken) + + claims, err := ParseJwtToken(customToken, customSecret) + if err != nil { + t.Fatalf("解析自定义token失败: %v", err) + } + + t.Logf("解析结果:") + t.Logf(" UserId: %d", claims.UserId) + t.Logf(" AgentId: %d", claims.AgentId) + t.Logf(" Platform: %s", claims.Platform) + t.Logf(" UserType: %d", claims.UserType) + t.Logf(" IsAgent: %d", claims.IsAgent) +} + +// TestGenerateAndParseWithRealData 生成一个真实的token并解析 +func TestGenerateAndParseWithRealData(t *testing.T) { + // 使用真实数据生成token + realClaims := JwtClaims{ + UserId: 1, + AgentId: 0, + Platform: "wxh5", + UserType: 0, + IsAgent: 0, + } + realSecret := "WUvoIwL-FK0qnlxhvxR9tV6SjfOpeJMpKmY2QvT99lA" + realExpire := int64(2592000) // 30天 + + // 生成token + token, err := GenerateJwtToken(realClaims, realSecret, realExpire) + if err != nil { + t.Fatalf("生成token失败: %v", err) + } + + t.Logf("=== 生成的完整token ===") + t.Logf("Token: %s", token) + t.Logf("========================") + + // 解析token + parsedClaims, err := ParseJwtToken(token, realSecret) + if err != nil { + t.Fatalf("解析token失败: %v", err) + } + + t.Logf("=== 解析结果 ===") + t.Logf("UserId: %d", parsedClaims.UserId) + t.Logf("AgentId: %d", parsedClaims.AgentId) + t.Logf("Platform: %s", parsedClaims.Platform) + t.Logf("UserType: %d", parsedClaims.UserType) + t.Logf("IsAgent: %d", parsedClaims.IsAgent) + t.Logf("================") + + // 验证数据一致性 + if parsedClaims.UserId != realClaims.UserId || + parsedClaims.AgentId != realClaims.AgentId || + parsedClaims.Platform != realClaims.Platform || + parsedClaims.UserType != realClaims.UserType || + parsedClaims.IsAgent != realClaims.IsAgent { + t.Error("解析出的claims与原始数据不一致") + } else { + t.Log("✅ 数据一致性验证通过") + } +} diff --git a/go.mod b/go.mod index daeffe6..df168d1 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartwalle/alipay/v3 v3.2.23 github.com/sony/sonyflake v1.2.0 + github.com/stretchr/testify v1.10.0 github.com/tidwall/gjson v1.18.0 github.com/wechatpay-apiv3/wechatpay-go v0.2.20 github.com/zeromicro/go-zero v1.7.3 @@ -42,6 +43,7 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clbanning/mxj/v2 v2.5.5 // indirect github.com/cloudwego/base64x v0.1.5 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.17.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect @@ -64,6 +66,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/openzipkin/zipkin-go v0.4.3 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect @@ -100,4 +103,5 @@ require ( google.golang.org/protobuf v1.35.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect )