github.com/database64128/shadowsocks-go@v1.7.0/api/v1/servers.go (about)

     1  package v1
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/database64128/shadowsocks-go/cred"
     7  	"github.com/database64128/shadowsocks-go/stats"
     8  	"github.com/gofiber/fiber/v2"
     9  )
    10  
    11  // ServerInfo contains information about the API server.
    12  type ServerInfo struct {
    13  	Name       string `json:"server"`
    14  	APIVersion string `json:"apiVersion"`
    15  }
    16  
    17  var serverInfo = ServerInfo{
    18  	Name:       "shadowsocks-go",
    19  	APIVersion: "v1",
    20  }
    21  
    22  // GetServerInfo returns information about the API server.
    23  func GetServerInfo(c *fiber.Ctx) error {
    24  	return c.JSON(&serverInfo)
    25  }
    26  
    27  type managedServer struct {
    28  	cms *cred.ManagedServer
    29  	sc  stats.Collector
    30  }
    31  
    32  // ServerManager handles server management API requests.
    33  type ServerManager struct {
    34  	managedServers     map[string]*managedServer
    35  	managedServerNames []string
    36  }
    37  
    38  // NewServerManager returns a new server manager.
    39  func NewServerManager() *ServerManager {
    40  	return &ServerManager{
    41  		managedServers: make(map[string]*managedServer),
    42  	}
    43  }
    44  
    45  // AddServer adds a server to the server manager.
    46  func (sm *ServerManager) AddServer(name string, cms *cred.ManagedServer, sc stats.Collector) {
    47  	sm.managedServers[name] = &managedServer{
    48  		cms: cms,
    49  		sc:  sc,
    50  	}
    51  	sm.managedServerNames = append(sm.managedServerNames, name)
    52  }
    53  
    54  // Routes sets up routes for the /v1/servers endpoint.
    55  func (sm *ServerManager) Routes(v1 fiber.Router) {
    56  	v1.Get("/servers", sm.ListServers)
    57  
    58  	server := v1.Group("/servers/:server", sm.GetManagedServer)
    59  	server.Get("", GetServerInfo)
    60  	server.Get("/stats", sm.GetStats)
    61  
    62  	users := server.Group("/users", sm.CheckMultiUserSupport)
    63  	users.Get("", sm.ListUsers)
    64  	users.Post("", sm.AddUser)
    65  	users.Get("/:username", sm.GetUser)
    66  	users.Patch("/:username", sm.UpdateUser)
    67  	users.Delete("/:username", sm.DeleteUser)
    68  }
    69  
    70  // ListServers lists all managed servers.
    71  func (sm *ServerManager) ListServers(c *fiber.Ctx) error {
    72  	return c.JSON(&sm.managedServerNames)
    73  }
    74  
    75  // GetManagedServer is a middleware for the servers group.
    76  // It adds the server with the given name to the request context.
    77  func (sm *ServerManager) GetManagedServer(c *fiber.Ctx) error {
    78  	name := c.Params("server")
    79  	ms := sm.managedServers[name]
    80  	if ms == nil {
    81  		return c.Status(fiber.StatusNotFound).JSON(&StandardError{Message: "server not found"})
    82  	}
    83  	c.Locals(0, ms)
    84  	return c.Next()
    85  }
    86  
    87  // GetStats returns server traffic statistics.
    88  func (sm *ServerManager) GetStats(c *fiber.Ctx) error {
    89  	var query struct {
    90  		Clear bool `query:"clear"`
    91  	}
    92  	if err := c.QueryParser(&query); err != nil {
    93  		return c.Status(fiber.StatusBadRequest).JSON(&StandardError{Message: err.Error()})
    94  	}
    95  
    96  	ms := c.Locals(0).(*managedServer)
    97  	if query.Clear {
    98  		return c.JSON(ms.sc.SnapshotAndReset())
    99  	}
   100  	return c.JSON(ms.sc.Snapshot())
   101  }
   102  
   103  // CheckMultiUserSupport is a middleware for the users group.
   104  // It checks whether the selected server supports user management.
   105  func (sm *ServerManager) CheckMultiUserSupport(c *fiber.Ctx) error {
   106  	ms := c.Locals(0).(*managedServer)
   107  	if ms.cms == nil {
   108  		return c.Status(fiber.StatusNotFound).JSON(&StandardError{Message: "The server does not support user management."})
   109  	}
   110  	return c.Next()
   111  }
   112  
   113  // UserList contains a list of user credentials.
   114  type UserList struct {
   115  	Users []cred.UserCredential `json:"users"`
   116  }
   117  
   118  // ListUsers lists server users.
   119  func (sm *ServerManager) ListUsers(c *fiber.Ctx) error {
   120  	ms := c.Locals(0).(*managedServer)
   121  	return c.JSON(&UserList{Users: ms.cms.Credentials()})
   122  }
   123  
   124  // AddUser adds a new user credential to the server.
   125  func (sm *ServerManager) AddUser(c *fiber.Ctx) error {
   126  	var uc cred.UserCredential
   127  	if err := c.BodyParser(&uc); err != nil {
   128  		return c.Status(fiber.StatusBadRequest).JSON(&StandardError{Message: err.Error()})
   129  	}
   130  
   131  	ms := c.Locals(0).(*managedServer)
   132  	if err := ms.cms.AddCredential(uc.Name, uc.UPSK); err != nil {
   133  		return c.Status(fiber.StatusBadRequest).JSON(&StandardError{Message: err.Error()})
   134  	}
   135  	return c.JSON(&uc)
   136  }
   137  
   138  // UserInfo contains information about a user.
   139  type UserInfo struct {
   140  	cred.UserCredential
   141  	stats.Traffic
   142  }
   143  
   144  // GetUser returns information about a user.
   145  func (sm *ServerManager) GetUser(c *fiber.Ctx) error {
   146  	ms := c.Locals(0).(*managedServer)
   147  	username := c.Params("username")
   148  	uc, ok := ms.cms.GetCredential(username)
   149  	if !ok {
   150  		return c.Status(fiber.StatusNotFound).JSON(&StandardError{Message: "user not found"})
   151  	}
   152  	return c.JSON(&UserInfo{uc, ms.sc.Snapshot().Traffic})
   153  }
   154  
   155  // UpdateUser updates a user's credential.
   156  func (sm *ServerManager) UpdateUser(c *fiber.Ctx) error {
   157  	var update struct {
   158  		UPSK []byte `json:"uPSK"`
   159  	}
   160  	if err := c.BodyParser(&update); err != nil {
   161  		return c.Status(fiber.StatusBadRequest).JSON(&StandardError{Message: err.Error()})
   162  	}
   163  
   164  	ms := c.Locals(0).(*managedServer)
   165  	username := c.Params("username")
   166  	if err := ms.cms.UpdateCredential(username, update.UPSK); err != nil {
   167  		if errors.Is(err, cred.ErrNonexistentUser) {
   168  			return c.Status(fiber.StatusNotFound).JSON(&StandardError{Message: err.Error()})
   169  		}
   170  		return c.Status(fiber.StatusBadRequest).JSON(&StandardError{Message: err.Error()})
   171  	}
   172  	return c.SendStatus(fiber.StatusNoContent)
   173  }
   174  
   175  // DeleteUser deletes a user's credential.
   176  func (sm *ServerManager) DeleteUser(c *fiber.Ctx) error {
   177  	ms := c.Locals(0).(*managedServer)
   178  	username := c.Params("username")
   179  	if err := ms.cms.DeleteCredential(username); err != nil {
   180  		return c.Status(fiber.StatusNotFound).JSON(&StandardError{Message: err.Error()})
   181  	}
   182  	return c.SendStatus(fiber.StatusNoContent)
   183  }