first commit
All checks were successful
build / build (api, amd64, linux) (push) Successful in -47s
build / build (api, arm64, linux) (push) Successful in -48s
build / build (api.exe, amd64, windows) (push) Successful in -47s

This commit is contained in:
CN-JS-HuiBai
2026-04-17 09:49:16 +08:00
commit 1ed31b9292
73 changed files with 16458 additions and 0 deletions

158
internal/service/plugin.go Normal file
View File

@@ -0,0 +1,158 @@
package service
import (
"crypto/md5"
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
"xboard-go/internal/database"
"xboard-go/internal/model"
"github.com/google/uuid"
)
const (
PluginRealNameVerification = "real_name_verification"
PluginUserOnlineDevices = "user_online_devices"
PluginUserAddIPv6 = "user_add_ipv6_subscription"
)
func GetPlugin(code string) (*model.Plugin, bool) {
var plugin model.Plugin
if err := database.DB.Where("code = ?", code).First(&plugin).Error; err != nil {
return nil, false
}
return &plugin, true
}
func IsPluginEnabled(code string) bool {
plugin, ok := GetPlugin(code)
return ok && plugin.IsEnabled
}
func GetPluginConfig(code string) map[string]any {
plugin, ok := GetPlugin(code)
if !ok || plugin.Config == nil || *plugin.Config == "" {
return map[string]any{}
}
var cfg map[string]any
if err := json.Unmarshal([]byte(*plugin.Config), &cfg); err != nil {
return map[string]any{}
}
return cfg
}
func GetPluginConfigString(code, key, defaultValue string) string {
cfg := GetPluginConfig(code)
value, ok := cfg[key]
if !ok {
return defaultValue
}
if raw, ok := value.(string); ok && raw != "" {
return raw
}
return defaultValue
}
func GetPluginConfigBool(code, key string, defaultValue bool) bool {
cfg := GetPluginConfig(code)
value, ok := cfg[key]
if !ok {
return defaultValue
}
switch typed := value.(type) {
case bool:
return typed
case float64:
return typed != 0
case string:
return typed == "1" || typed == "true"
default:
return defaultValue
}
}
func SyncIPv6ShadowAccount(user *model.User) bool {
if user == nil || user.PlanID == nil {
return false
}
var plan model.Plan
if err := database.DB.First(&plan, *user.PlanID).Error; err != nil {
return false
}
if !PluginPlanAllowed(&plan) {
return false
}
ipv6Email := IPv6ShadowEmail(user.Email)
var ipv6User model.User
now := time.Now().Unix()
if err := database.DB.Where("email = ?", ipv6Email).First(&ipv6User).Error; err != nil {
ipv6User = *user
ipv6User.ID = 0
ipv6User.Email = ipv6Email
ipv6User.UUID = uuid.New().String()
ipv6User.Token = fmt.Sprintf("%x", md5.Sum([]byte(time.Now().String()+ipv6Email)))[:16]
ipv6User.U = 0
ipv6User.D = 0
ipv6User.T = 0
ipv6User.ParentID = &user.ID
ipv6User.CreatedAt = now
}
ipv6User.Email = ipv6Email
ipv6User.Password = user.Password
ipv6User.U = 0
ipv6User.D = 0
ipv6User.T = 0
ipv6User.UpdatedAt = now
if planID := parsePluginPositiveInt(GetPluginConfigString(PluginUserAddIPv6, "ipv6_plan_id", "0"), 0); planID > 0 {
ipv6User.PlanID = &planID
}
if groupID := parsePluginPositiveInt(GetPluginConfigString(PluginUserAddIPv6, "ipv6_group_id", "0"), 0); groupID > 0 {
ipv6User.GroupID = &groupID
}
return database.DB.Save(&ipv6User).Error == nil
}
func PluginPlanAllowed(plan *model.Plan) bool {
if plan == nil {
return false
}
for _, raw := range strings.Split(GetPluginConfigString(PluginUserAddIPv6, "allowed_plans", ""), ",") {
if parsePluginPositiveInt(strings.TrimSpace(raw), 0) == plan.ID {
return true
}
}
referenceFlag := strings.ToLower(GetPluginConfigString(PluginUserAddIPv6, "reference_flag", "ipv6"))
reference := ""
if plan.Reference != nil {
reference = strings.ToLower(*plan.Reference)
}
return referenceFlag != "" && strings.Contains(reference, referenceFlag)
}
func IPv6ShadowEmail(email string) string {
suffix := GetPluginConfigString(PluginUserAddIPv6, "email_suffix", "-ipv6")
parts := strings.SplitN(email, "@", 2)
if len(parts) != 2 {
return email
}
return parts[0] + suffix + "@" + parts[1]
}
func parsePluginPositiveInt(raw string, defaultValue int) int {
value, err := strconv.Atoi(strings.TrimSpace(raw))
if err != nil || value <= 0 {
return defaultValue
}
return value
}