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 }