Добавил изменения конфига
This commit is contained in:
parent
b6866f8540
commit
4c2f052d70
5 changed files with 223 additions and 62 deletions
12
miku/go.mod
12
miku/go.mod
|
|
@ -4,6 +4,14 @@ go 1.24.2
|
||||||
|
|
||||||
replace miku/users => ../users/
|
replace miku/users => ../users/
|
||||||
|
|
||||||
require miku/users v0.0.0-00010101000000-000000000000
|
require (
|
||||||
|
github.com/urfave/cli/v3 v3.3.2
|
||||||
|
miku/supporter v0.0.0-00010101000000-000000000000
|
||||||
|
)
|
||||||
|
|
||||||
require github.com/google/uuid v1.6.0 // indirect
|
require (
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
miku/users v0.0.0-00010101000000-000000000000 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
replace miku/supporter => ../supporter
|
||||||
|
|
|
||||||
144
miku/main.go
144
miku/main.go
|
|
@ -1,28 +1,142 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"miku/users"
|
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"miku/supporter"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var confFile map[string]interface{}
|
cmd := &cli.Command{
|
||||||
file, err := os.ReadFile("../testconfig.json")
|
Name: "miku",
|
||||||
if err != nil {
|
Usage: "Управление пользователями Vless в конфиге sing-box",
|
||||||
fmt.Println(err)
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "Добавить пользователя в config.json",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Value: "/etc/sing-box/config.json",
|
||||||
|
Usage: "Указывает местоположение конфига",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "domain",
|
||||||
|
Aliases: []string{"d"},
|
||||||
|
Value: "vpn.catgirls.asia",
|
||||||
|
Usage: "Указывает доменное имя, по которому клиенты могут выполнять подключение",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(ctx context.Context, c *cli.Command) error {
|
||||||
|
var confFile map[string]any
|
||||||
|
configPath, ok := c.Flags[0].Get().(string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("не удалось преобразовать тип")
|
||||||
|
}
|
||||||
|
fullpath, err := filepath.Abs(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Println(fullpath)
|
||||||
|
file, err := os.ReadFile(fullpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
json.Unmarshal(file, &confFile)
|
||||||
|
vlessUsers, err := supporter.MapToStruct(confFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vlessUsers, err = vlessUsers.Add(c.Args().First())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fileToWrite, err := os.OpenFile(fullpath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newConfig, err := supporter.StructToConfig(vlessUsers, confFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newJson, err := json.MarshalIndent(newConfig, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fileToWrite.Write(newJson)
|
||||||
|
fmt.Printf("Пользователь %s добавлен в конфиг %s", c.Args().First(), fullpath)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "delete",
|
||||||
|
Aliases: []string{"del", "d"},
|
||||||
|
Usage: "Удаление пользователя из конфига Vless",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Value: "/etc/sing-box/config.json",
|
||||||
|
Usage: "Указывает местоположение конфига",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "domain",
|
||||||
|
Aliases: []string{"d"},
|
||||||
|
Value: "vpn.catgirls.asia",
|
||||||
|
Usage: "Указывает доменное имя, по которому клиенты могут выполнять подключение",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(ctx context.Context, c *cli.Command) error {
|
||||||
|
var confFile map[string]any
|
||||||
|
configPath, ok := c.Flags[0].Get().(string)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("не удалось преобразовать тип")
|
||||||
|
}
|
||||||
|
fullpath, err := filepath.Abs(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fmt.Println(fullpath)
|
||||||
|
file, err := os.ReadFile(fullpath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
json.Unmarshal(file, &confFile)
|
||||||
|
vlessUsers, err := supporter.MapToStruct(confFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
vlessUsers = vlessUsers.Del(c.Args().First())
|
||||||
|
fileToWrite, err := os.OpenFile(fullpath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newConfig, err := supporter.StructToConfig(vlessUsers, confFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
newJson, err := json.MarshalIndent(newConfig, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
fileToWrite.Write(newJson)
|
||||||
|
fmt.Printf("Пользователь %s удален из конфига %s", c.Args().First(), fullpath)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(file, &confFile)
|
if err := cmd.Run(context.Background(), os.Args); err != nil {
|
||||||
if err != nil {
|
log.Fatal(err)
|
||||||
fmt.Println(err)
|
|
||||||
}
|
}
|
||||||
vlessUsers := users.MapToStruct(confFile)
|
|
||||||
newUsers := vlessUsers.Add("test")
|
|
||||||
newConfFile, err := users.StructToConfig(newUsers, confFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
log.Println(newConfFile)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
supporter/go.mod
Normal file
10
supporter/go.mod
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
module miku/supporter
|
||||||
|
|
||||||
|
go 1.24.2
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
|
miku/users v0.0.0-00010101000000-000000000000
|
||||||
|
)
|
||||||
|
|
||||||
|
replace miku/users => ../users
|
||||||
52
supporter/supporter.go
Normal file
52
supporter/supporter.go
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
package supporter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"miku/users"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MapToStruct(toStructMap map[string]any) (users.VLESSUsers, error) {
|
||||||
|
var vlessUsers users.VLESSUsers
|
||||||
|
inbounds, ok := toStructMap["inbounds"].([]any)
|
||||||
|
if !ok || len(inbounds) == 0 {
|
||||||
|
return nil, errors.New("нет inbounds")
|
||||||
|
}
|
||||||
|
firstInbound, ok := inbounds[0].(map[string]any)
|
||||||
|
if !ok || len(firstInbound) == 0 {
|
||||||
|
return nil, errors.New("неизвестный формат inbound")
|
||||||
|
}
|
||||||
|
usedMap, ok := firstInbound["users"].([]any)
|
||||||
|
if !ok || len(usedMap) == 0 {
|
||||||
|
return nil, errors.New("неизвестный формат пользователей")
|
||||||
|
}
|
||||||
|
for _, curretMap := range usedMap {
|
||||||
|
userMap := curretMap.(map[string]any)
|
||||||
|
vlessUsers = append(vlessUsers, struct {
|
||||||
|
Name string "json:\"name\""
|
||||||
|
UUID uuid.UUID "json:\"uuid\""
|
||||||
|
}{
|
||||||
|
Name: userMap["name"].(string),
|
||||||
|
UUID: uuid.MustParse(userMap["uuid"].(string)),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return vlessUsers, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func StructToConfig(vlessUsers users.VLESSUsers, configMap map[string]any) (map[string]any, error) {
|
||||||
|
var toInterface []map[string]any
|
||||||
|
newConfigMap := configMap
|
||||||
|
structJson, err := json.Marshal(vlessUsers)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(structJson, &toInterface)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
newConfigMap["inbounds"].([]any)[0].(map[string]any)["users"] = toInterface
|
||||||
|
return newConfigMap, nil
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,20 @@
|
||||||
package users
|
package users
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"errors"
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VLESSUsers []struct {
|
type User struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
UUID uuid.UUID `json:"uuid"`
|
UUID uuid.UUID `json:"uuid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type VLESSUsers []User
|
||||||
|
|
||||||
func (u VLESSUsers) Del(user string) VLESSUsers {
|
func (u VLESSUsers) Del(user string) VLESSUsers {
|
||||||
var newU VLESSUsers
|
var newU VLESSUsers = make(VLESSUsers, 0, len(u))
|
||||||
for _, v := range u {
|
for _, v := range u {
|
||||||
if v.Name != user {
|
if v.Name != user {
|
||||||
newU = append(newU, v)
|
newU = append(newU, v)
|
||||||
|
|
@ -22,52 +23,28 @@ func (u VLESSUsers) Del(user string) VLESSUsers {
|
||||||
return newU
|
return newU
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u VLESSUsers) Add(user string) VLESSUsers {
|
func (u VLESSUsers) checkInConfig(userName string) bool {
|
||||||
var userStruct struct {
|
for _, v := range u {
|
||||||
Name string
|
if v.Name == userName {
|
||||||
UUID uuid.UUID
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
userStruct.Name = user
|
return false
|
||||||
randUUID, err := uuid.NewUUID()
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
userStruct.UUID = randUUID
|
|
||||||
|
|
||||||
newU := append(u, struct {
|
|
||||||
Name string "json:\"name\""
|
|
||||||
UUID uuid.UUID "json:\"uuid\""
|
|
||||||
}(userStruct))
|
|
||||||
return newU
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapToStruct(toStructMap map[string]interface{}) VLESSUsers {
|
func (u VLESSUsers) Add(userName string) (VLESSUsers, error) {
|
||||||
var vlessUsers VLESSUsers
|
|
||||||
usedMap := toStructMap["inbounds"].([]interface{})[0].(map[string]interface{})["users"].([]interface{})
|
|
||||||
for _, curretMap := range usedMap {
|
|
||||||
userMap := curretMap.(map[string]interface{})
|
|
||||||
vlessUsers = append(vlessUsers, struct {
|
|
||||||
Name string "json:\"name\""
|
|
||||||
UUID uuid.UUID "json:\"uuid\""
|
|
||||||
}{
|
|
||||||
Name: userMap["name"].(string),
|
|
||||||
UUID: uuid.MustParse(userMap["uuid"].(string)),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return vlessUsers
|
|
||||||
}
|
|
||||||
|
|
||||||
func StructToConfig(vlessUsers VLESSUsers, configMap map[string]interface{}) (map[string]interface{}, error) {
|
if u.checkInConfig(userName) {
|
||||||
var toInterface []map[string]interface{}
|
return nil, errors.New("пользователь уже добавлен в конфиг")
|
||||||
newConfigMap := configMap
|
|
||||||
structJson, err := json.Marshal(vlessUsers)
|
|
||||||
if err != nil {
|
|
||||||
return map[string]interface{}{}, err
|
|
||||||
}
|
}
|
||||||
err = json.Unmarshal(structJson, &toInterface)
|
|
||||||
|
newUUID, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return map[string]interface{}{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
newConfigMap["inbounds"].([]interface{})[0].(map[string]interface{})["users"] = toInterface
|
newUser := User{
|
||||||
return newConfigMap, nil
|
Name: userName,
|
||||||
|
UUID: newUUID,
|
||||||
|
}
|
||||||
|
return append(u, newUser), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue