feat: bind device limit

This commit is contained in:
EUForest 2026-01-06 16:15:47 +08:00
parent ec0a0f968e
commit 23ef9dbff1
4 changed files with 72 additions and 0 deletions

View File

@ -152,6 +152,7 @@ type (
EnableIpRegisterLimit bool `json:"enable_ip_register_limit"`
IpRegisterLimit int64 `json:"ip_register_limit"`
IpRegisterLimitDuration int64 `json:"ip_register_limit_duration"`
DeviceLimit int64 `json:"device_limit"`
}
VerifyConfig {
TurnstileSiteKey string `json:"turnstile_site_key"`
@ -456,6 +457,7 @@ type (
SubscribePlan int64 `json:"subscribe_plan"`
UnitTime string `json:"unit_time"`
Quantity int64 `json:"quantity"`
Status int64 `json:"status"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}

View File

@ -73,6 +73,7 @@ type RegisterConfig struct {
IpRegisterLimit int64 `yaml:"IpRegisterLimit" default:"0"`
IpRegisterLimitDuration int64 `yaml:"IpRegisterLimitDuration" default:"0"`
EnableIpRegisterLimit bool `yaml:"EnableIpRegisterLimit" default:"false"`
DeviceLimit int64 `yaml:"DeviceLimit" default:"5"`
}
type EmailConfig struct {

View File

@ -89,6 +89,36 @@ func (l *BindDeviceLogic) createDeviceForUser(identifier, ip, userAgent string,
logger.Field("user_id", userId),
)
// Check device limit
deviceLimit := l.svcCtx.Config.Register.DeviceLimit
if deviceLimit > 0 {
// Count current user's devices
var deviceCount int64
if err := l.svcCtx.DB.Model(&user.Device{}).Where("user_id = ?", userId).Count(&deviceCount).Error; err != nil {
l.Errorw("failed to count user devices",
logger.Field("user_id", userId),
logger.Field("error", err.Error()),
)
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count devices failed: %v", err.Error())
}
// Check if limit reached
if deviceCount >= deviceLimit {
l.Errorw("device limit reached",
logger.Field("user_id", userId),
logger.Field("device_count", deviceCount),
logger.Field("device_limit", deviceLimit),
)
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device limit reached: maximum %d devices allowed", deviceLimit)
}
l.Infow("device limit check passed",
logger.Field("user_id", userId),
logger.Field("device_count", deviceCount),
logger.Field("device_limit", deviceLimit),
)
}
err := l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error {
// Create device auth method
authMethod := &user.AuthMethods{
@ -147,6 +177,37 @@ func (l *BindDeviceLogic) createDeviceForUser(identifier, ip, userAgent string,
func (l *BindDeviceLogic) rebindDeviceToNewUser(deviceInfo *user.Device, ip, userAgent string, newUserId int64) error {
oldUserId := deviceInfo.UserId
// Check device limit for new user
deviceLimit := l.svcCtx.Config.Register.DeviceLimit
if deviceLimit > 0 {
// Count new user's current devices (excluding the one being rebound)
var deviceCount int64
if err := l.svcCtx.DB.Model(&user.Device{}).Where("user_id = ? AND id != ?", newUserId, deviceInfo.Id).Count(&deviceCount).Error; err != nil {
l.Errorw("failed to count new user devices",
logger.Field("user_id", newUserId),
logger.Field("error", err.Error()),
)
return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count devices failed: %v", err.Error())
}
// Check if limit reached
if deviceCount >= deviceLimit {
l.Errorw("device limit reached for new user",
logger.Field("user_id", newUserId),
logger.Field("device_count", deviceCount),
logger.Field("device_limit", deviceLimit),
)
return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "device limit reached: maximum %d devices allowed", deviceLimit)
}
l.Infow("device limit check passed for rebinding",
logger.Field("user_id", newUserId),
logger.Field("device_count", deviceCount),
logger.Field("device_limit", deviceLimit),
)
}
var users []*user.User
err := l.svcCtx.DB.Where("id in (?)", []int64{oldUserId, newUserId}).Find(&users).Error
if err != nil {

View File

@ -1836,6 +1836,7 @@ type RedemptionCode struct {
SubscribePlan int64 `json:"subscribe_plan"`
UnitTime string `json:"unit_time"`
Quantity int64 `json:"quantity"`
Status int64 `json:"status"`
CreatedAt int64 `json:"created_at"`
UpdatedAt int64 `json:"updated_at"`
}
@ -1860,6 +1861,7 @@ type RegisterConfig struct {
EnableIpRegisterLimit bool `json:"enable_ip_register_limit"`
IpRegisterLimit int64 `json:"ip_register_limit"`
IpRegisterLimitDuration int64 `json:"ip_register_limit_duration"`
DeviceLimit int64 `json:"device_limit"`
}
type RegisterLog struct {
@ -2318,6 +2320,11 @@ type ToggleNodeStatusRequest struct {
Enable *bool `json:"enable"`
}
type ToggleRedemptionCodeStatusRequest struct {
Id int64 `json:"id" validate:"required"`
Status int64 `json:"status" validate:"oneof=0 1"`
}
type ToggleUserSubscribeStatusRequest struct {
UserSubscribeId int64 `json:"user_subscribe_id"`
}
@ -2494,6 +2501,7 @@ type UpdateRedemptionCodeRequest struct {
SubscribePlan int64 `json:"subscribe_plan,omitempty"`
UnitTime string `json:"unit_time,omitempty" validate:"omitempty,oneof=day month quarter half_year year"`
Quantity int64 `json:"quantity,omitempty"`
Status int64 `json:"status,omitempty" validate:"omitempty,oneof=0 1"`
}
type UpdateServerRequest struct {