1
0

inbound_master_push_test.go 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. package controller
  2. import (
  3. "context"
  4. "net/http/httptest"
  5. "net/url"
  6. "path/filepath"
  7. "strconv"
  8. "strings"
  9. "testing"
  10. "github.com/gin-gonic/gin"
  11. "github.com/mhsanaei/3x-ui/v3/internal/database"
  12. "github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
  13. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  14. "github.com/mhsanaei/3x-ui/v3/internal/util/crypto"
  15. "github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
  16. )
  17. // A node enrolled with an admin-scope token (the -getApiToken default) must
  18. // still store the clients its master pushes; it used to keep its own list.
  19. func TestMasterPushWithAdminTokenAppliesClients(t *testing.T) {
  20. gin.SetMode(gin.TestMode)
  21. dbDir := t.TempDir()
  22. t.Setenv("XUI_DB_FOLDER", dbDir)
  23. dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
  24. prev := runtime.GetManager()
  25. runtime.SetManager(runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }, SetNeedRestart: func() {}}))
  26. t.Cleanup(func() { runtime.SetManager(prev) })
  27. const token = "admin-node-token"
  28. if err := database.GetDB().Create(&model.ApiToken{
  29. Name: "node", Token: crypto.HashTokenSHA256(token), Enabled: true, Scope: model.ApiScopeAdmin,
  30. }).Error; err != nil {
  31. t.Fatalf("seed token: %v", err)
  32. }
  33. var owner model.User
  34. if err := database.GetDB().First(&owner).Error; err != nil {
  35. t.Fatalf("load panel user: %v", err)
  36. }
  37. const stream = `{"network":"tcp","security":"none","tcpSettings":{"header":{"type":"none"}}}`
  38. stored := &model.Inbound{
  39. UserId: owner.Id, Tag: "in-46001", Protocol: model.VLESS, Port: 46001, Enable: true,
  40. Settings: `{"clients":[],"decryption":"none"}`, StreamSettings: stream, Sniffing: `{}`,
  41. }
  42. if err := database.GetDB().Create(stored).Error; err != nil {
  43. t.Fatalf("seed node inbound: %v", err)
  44. }
  45. engine := gin.New()
  46. a := &APIController{}
  47. api := engine.Group("/panel/api")
  48. api.Use(a.checkAPIAuth, a.enforceTokenScope)
  49. NewInboundController(api.Group("/inbounds"))
  50. srv := httptest.NewServer(engine)
  51. defer srv.Close()
  52. u, _ := url.Parse(srv.URL)
  53. port, _ := strconv.Atoi(u.Port())
  54. master := runtime.NewRemote(&model.Node{
  55. Id: 1, Name: "n1", Scheme: "http", Address: u.Hostname(), Port: port,
  56. BasePath: "/", ApiToken: token, Enable: true, AllowPrivateAddress: true,
  57. }, nil)
  58. pushed := *stored
  59. pushed.Settings = `{"clients":[{"id":"7fa0b7d1-9b5f-47ad-bef2-6cb0c4a624be","email":"alice","enable":true,"subId":"s-alice"}],"decryption":"none"}`
  60. if err := master.UpdateInbound(context.Background(), &pushed, &pushed); err != nil {
  61. t.Fatalf("master push: %v", err)
  62. }
  63. var got model.Inbound
  64. if err := database.GetDB().First(&got, stored.Id).Error; err != nil {
  65. t.Fatalf("reload node inbound: %v", err)
  66. }
  67. if !strings.Contains(got.Settings, `"alice"`) {
  68. t.Fatalf("node kept its own client list after a master push: %s", got.Settings)
  69. }
  70. }