334 lines
8.2 KiB
Go
334 lines
8.2 KiB
Go
package service
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"s-ui/database"
|
|
"s-ui/database/model"
|
|
"s-ui/util"
|
|
"s-ui/util/common"
|
|
"strings"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type InboundService struct{}
|
|
|
|
func (s *InboundService) Get(ids string) (*[]map[string]interface{}, error) {
|
|
if ids == "" {
|
|
return s.GetAll()
|
|
}
|
|
return s.getById(ids)
|
|
}
|
|
|
|
func (s *InboundService) getById(ids string) (*[]map[string]interface{}, error) {
|
|
var inbound []model.Inbound
|
|
var result []map[string]interface{}
|
|
db := database.GetDB()
|
|
err := db.Model(model.Inbound{}).Where("id in ?", strings.Split(ids, ",")).Scan(&inbound).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, inb := range inbound {
|
|
inbData, err := inb.MarshalFull()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result = append(result, *inbData)
|
|
}
|
|
return &result, nil
|
|
}
|
|
|
|
func (s *InboundService) GetAll() (*[]map[string]interface{}, error) {
|
|
db := database.GetDB()
|
|
inbounds := []model.Inbound{}
|
|
err := db.Model(model.Inbound{}).Scan(&inbounds).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var data []map[string]interface{}
|
|
for _, inbound := range inbounds {
|
|
var shadowtls_version uint
|
|
inbData := map[string]interface{}{
|
|
"id": inbound.Id,
|
|
"type": inbound.Type,
|
|
"tag": inbound.Tag,
|
|
"tls_id": inbound.TlsId,
|
|
}
|
|
if inbound.Options != nil {
|
|
var restFields map[string]json.RawMessage
|
|
if err := json.Unmarshal(inbound.Options, &restFields); err != nil {
|
|
return nil, err
|
|
}
|
|
inbData["listen"] = restFields["listen"]
|
|
inbData["listen_port"] = restFields["listen_port"]
|
|
if inbound.Type == "shadowtls" {
|
|
json.Unmarshal(restFields["version"], &shadowtls_version)
|
|
}
|
|
}
|
|
if s.hasUser(inbound.Type) {
|
|
if inbound.Type == "shadowtls" && shadowtls_version < 3 {
|
|
break
|
|
}
|
|
users := []string{}
|
|
err = db.Raw("SELECT clients.name FROM clients, json_each(clients.inbounds) as je WHERE je.value = ?", inbound.Id).Scan(&users).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
inbData["users"] = users
|
|
}
|
|
|
|
data = append(data, inbData)
|
|
}
|
|
return &data, nil
|
|
}
|
|
|
|
func (s *InboundService) FromIds(ids []uint) ([]*model.Inbound, error) {
|
|
db := database.GetDB()
|
|
inbounds := []*model.Inbound{}
|
|
err := db.Model(model.Inbound{}).Where("id in ?", ids).Scan(&inbounds).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return inbounds, nil
|
|
}
|
|
|
|
func (s *InboundService) Save(tx *gorm.DB, act string, data json.RawMessage, initUserIds string, hostname string) (uint, error) {
|
|
var err error
|
|
var id uint
|
|
|
|
switch act {
|
|
case "new", "edit":
|
|
var inbound model.Inbound
|
|
err = inbound.UnmarshalJSON(data)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if inbound.TlsId > 0 {
|
|
err = tx.Model(model.Tls{}).Where("id = ?", inbound.TlsId).Find(&inbound.Tls).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
err = util.FillOutJson(&inbound, hostname)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
err = tx.Save(&inbound).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
id = inbound.Id
|
|
|
|
if corePtr.IsRunning() {
|
|
if act == "edit" {
|
|
var oldTag string
|
|
err = tx.Model(model.Inbound{}).Select("tag").Where("id = ?", inbound.Id).Find(&oldTag).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
err = corePtr.RemoveInbound(oldTag)
|
|
if err != nil && err != os.ErrInvalid {
|
|
return 0, err
|
|
}
|
|
}
|
|
|
|
inboundConfig, err := inbound.MarshalJSON()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if act == "edit" {
|
|
inboundConfig, err = s.addUsers(tx, inboundConfig, inbound.Id, inbound.Type)
|
|
} else {
|
|
inboundConfig, err = s.initUsers(tx, inboundConfig, initUserIds, inbound.Type)
|
|
}
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
err = corePtr.AddInbound(inboundConfig)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
case "del":
|
|
var tag string
|
|
err = json.Unmarshal(data, &tag)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if corePtr.IsRunning() {
|
|
err = corePtr.RemoveInbound(tag)
|
|
if err != nil && err != os.ErrInvalid {
|
|
return 0, err
|
|
}
|
|
}
|
|
err = tx.Model(model.Inbound{}).Select("id").Where("tag = ?", tag).Scan(&id).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
err = tx.Where("tag = ?", tag).Delete(model.Inbound{}).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
default:
|
|
return 0, common.NewErrorf("unknown action: %s", act)
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func (s *InboundService) UpdateOutJsons(tx *gorm.DB, inboundIds []uint, hostname string) error {
|
|
var inbounds []model.Inbound
|
|
err := tx.Model(model.Inbound{}).Preload("Tls").Where("id in ?", inboundIds).Find(&inbounds).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, inbound := range inbounds {
|
|
err = util.FillOutJson(&inbound, hostname)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = tx.Model(model.Inbound{}).Where("tag = ?", inbound.Tag).Update("out_json", inbound.OutJson).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *InboundService) GetAllConfig(db *gorm.DB) ([]json.RawMessage, error) {
|
|
var inboundsJson []json.RawMessage
|
|
var inbounds []*model.Inbound
|
|
err := db.Model(model.Inbound{}).Preload("Tls").Find(&inbounds).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, inbound := range inbounds {
|
|
inboundJson, err := inbound.MarshalJSON()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
inboundJson, err = s.addUsers(db, inboundJson, inbound.Id, inbound.Type)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
inboundsJson = append(inboundsJson, inboundJson)
|
|
}
|
|
return inboundsJson, nil
|
|
}
|
|
|
|
func (s *InboundService) hasUser(inboundType string) bool {
|
|
switch inboundType {
|
|
case "mixed", "socks", "http", "shadowsocks", "vmess", "trojan", "naive", "hysteria", "shadowtls", "tuic", "hysteria2", "vless":
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (s *InboundService) fetchUsers(db *gorm.DB, inboundType string, condition string, inbound map[string]interface{}) ([]json.RawMessage, error) {
|
|
if inboundType == "shadowtls" {
|
|
version, _ := inbound["version"].(float64)
|
|
if int(version) < 3 {
|
|
return nil, nil
|
|
}
|
|
}
|
|
if inboundType == "shadowsocks" {
|
|
method, _ := inbound["method"].(string)
|
|
if method == "2022-blake3-aes-128-gcm" {
|
|
inboundType = "shadowsocks16"
|
|
}
|
|
}
|
|
|
|
var users []string
|
|
err := db.Raw(`SELECT json_extract(clients.config, ?) FROM clients WHERE enable = true AND ?`,
|
|
"$."+inboundType, condition).Scan(&users).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var usersJson []json.RawMessage
|
|
for _, user := range users {
|
|
if inboundType == "vless" && inbound["tls"] == nil {
|
|
user = strings.Replace(user, "xtls-rprx-vision", "", -1)
|
|
}
|
|
usersJson = append(usersJson, json.RawMessage(user))
|
|
}
|
|
return usersJson, nil
|
|
}
|
|
|
|
func (s *InboundService) addUsers(db *gorm.DB, inboundJson []byte, inboundId uint, inboundType string) ([]byte, error) {
|
|
if !s.hasUser(inboundType) {
|
|
return inboundJson, nil
|
|
}
|
|
|
|
var inbound map[string]interface{}
|
|
err := json.Unmarshal(inboundJson, &inbound)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
condition := fmt.Sprintf("%d IN (SELECT json_each.value FROM json_each(clients.inbounds))", inboundId)
|
|
inbound["users"], err = s.fetchUsers(db, inboundType, condition, inbound)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return json.Marshal(inbound)
|
|
}
|
|
|
|
func (s *InboundService) initUsers(db *gorm.DB, inboundJson []byte, clientIds string, inboundType string) ([]byte, error) {
|
|
ClientIds := strings.Split(clientIds, ",")
|
|
if len(ClientIds) == 0 {
|
|
return inboundJson, nil
|
|
}
|
|
|
|
if !s.hasUser(inboundType) {
|
|
return inboundJson, nil
|
|
}
|
|
|
|
var inbound map[string]interface{}
|
|
err := json.Unmarshal(inboundJson, &inbound)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
condition := fmt.Sprintf("id IN (%s)", strings.Join(ClientIds, ","))
|
|
inbound["users"], err = s.fetchUsers(db, inboundType, condition, inbound)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return json.Marshal(inbound)
|
|
}
|
|
|
|
func (s *InboundService) RestartInbounds(tx *gorm.DB, ids []uint) error {
|
|
var inbounds []*model.Inbound
|
|
err := tx.Model(model.Inbound{}).Preload("Tls").Where("id in ?", ids).Find(&inbounds).Error
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, inbound := range inbounds {
|
|
err = corePtr.RemoveInbound(inbound.Tag)
|
|
if err != nil && err != os.ErrInvalid {
|
|
return err
|
|
}
|
|
inboundConfig, err := inbound.MarshalJSON()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
inboundConfig, err = s.addUsers(tx, inboundConfig, inbound.Id, inbound.Type)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
err = corePtr.AddInbound(inboundConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|