api.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. package ssmapi
  2. import (
  3. C "github.com/sagernet/sing-box/constant"
  4. "github.com/sagernet/sing/common"
  5. "net/http"
  6. "github.com/go-chi/chi/v5"
  7. "github.com/go-chi/render"
  8. )
  9. func (s *Server) setupRoutes(r chi.Router) {
  10. r.Group(func(r chi.Router) {
  11. r.Get("/", s.getServerInfo)
  12. r.Get("/nodes", s.getNodes)
  13. r.Post("/nodes", s.addNode)
  14. r.Get("/nodes/{id}", s.getNode)
  15. r.Put("/nodes/{id}", s.updateNode)
  16. r.Delete("/nodes/{id}", s.deleteNode)
  17. r.Get("/users", s.listUser)
  18. r.Post("/users", s.addUser)
  19. r.Get("/users/{username}", s.getUser)
  20. r.Put("/users/{username}", s.updateUser)
  21. r.Delete("/users/{username}", s.deleteUser)
  22. r.Get("/stats", s.getStats)
  23. })
  24. }
  25. func (s *Server) getServerInfo(writer http.ResponseWriter, request *http.Request) {
  26. render.JSON(writer, request, render.M{
  27. "server": "sing-box",
  28. "apiVersion": "v1",
  29. "_sing_box_version": C.Version,
  30. })
  31. }
  32. func (s *Server) getNodes(writer http.ResponseWriter, request *http.Request) {
  33. var response struct {
  34. Protocols []string `json:"protocols"`
  35. Shadowsocks []ShadowsocksNodeObject `json:"shadowsocks,omitempty"`
  36. }
  37. for _, node := range s.nodes {
  38. if !common.Contains(response.Protocols, node.Protocol()) {
  39. response.Protocols = append(response.Protocols, node.Protocol())
  40. }
  41. switch node.Protocol() {
  42. case C.TypeShadowsocks:
  43. response.Shadowsocks = append(response.Shadowsocks, node.Shadowsocks())
  44. }
  45. }
  46. render.JSON(writer, request, &response)
  47. }
  48. func (s *Server) addNode(writer http.ResponseWriter, request *http.Request) {
  49. writer.WriteHeader(http.StatusNotImplemented)
  50. }
  51. func (s *Server) getNode(writer http.ResponseWriter, request *http.Request) {
  52. nodeID := chi.URLParam(request, "id")
  53. if nodeID == "" {
  54. writer.WriteHeader(http.StatusBadRequest)
  55. return
  56. }
  57. for _, node := range s.nodes {
  58. if nodeID == node.ID() {
  59. render.JSON(writer, request, render.M{
  60. node.Protocol(): node.Object(),
  61. })
  62. return
  63. }
  64. }
  65. }
  66. func (s *Server) updateNode(writer http.ResponseWriter, request *http.Request) {
  67. writer.WriteHeader(http.StatusNotImplemented)
  68. }
  69. func (s *Server) deleteNode(writer http.ResponseWriter, request *http.Request) {
  70. writer.WriteHeader(http.StatusNotImplemented)
  71. }
  72. type SSMUserObject struct {
  73. UserName string `json:"username"`
  74. Password string `json:"uPSK,omitempty"`
  75. DownlinkBytes int64 `json:"downlinkBytes"`
  76. UplinkBytes int64 `json:"uplinkBytes"`
  77. DownlinkPackets int64 `json:"downlinkPackets"`
  78. UplinkPackets int64 `json:"uplinkPackets"`
  79. TCPSessions int64 `json:"tcpSessions"`
  80. UDPSessions int64 `json:"udpSessions"`
  81. }
  82. func (s *Server) listUser(writer http.ResponseWriter, request *http.Request) {
  83. render.JSON(writer, request, render.M{
  84. "users": s.userManager.List(),
  85. })
  86. }
  87. func (s *Server) addUser(writer http.ResponseWriter, request *http.Request) {
  88. var addRequest struct {
  89. UserName string `json:"username"`
  90. Password string `json:"uPSK"`
  91. }
  92. err := render.DecodeJSON(request.Body, &addRequest)
  93. if err != nil {
  94. render.Status(request, http.StatusBadRequest)
  95. render.PlainText(writer, request, err.Error())
  96. return
  97. }
  98. err = s.userManager.Add(addRequest.UserName, addRequest.Password)
  99. if err != nil {
  100. render.Status(request, http.StatusBadRequest)
  101. render.PlainText(writer, request, err.Error())
  102. return
  103. }
  104. writer.WriteHeader(http.StatusCreated)
  105. }
  106. func (s *Server) getUser(writer http.ResponseWriter, request *http.Request) {
  107. userName := chi.URLParam(request, "username")
  108. if userName == "" {
  109. writer.WriteHeader(http.StatusBadRequest)
  110. return
  111. }
  112. uPSK, loaded := s.userManager.Get(userName)
  113. if !loaded {
  114. writer.WriteHeader(http.StatusNotFound)
  115. return
  116. }
  117. user := SSMUserObject{
  118. UserName: userName,
  119. Password: uPSK,
  120. }
  121. s.trafficManager.ReadUser(&user)
  122. render.JSON(writer, request, user)
  123. }
  124. func (s *Server) updateUser(writer http.ResponseWriter, request *http.Request) {
  125. userName := chi.URLParam(request, "username")
  126. if userName == "" {
  127. writer.WriteHeader(http.StatusBadRequest)
  128. return
  129. }
  130. var updateRequest struct {
  131. Password string `json:"uPSK"`
  132. }
  133. err := render.DecodeJSON(request.Body, &updateRequest)
  134. if err != nil {
  135. render.Status(request, http.StatusBadRequest)
  136. render.PlainText(writer, request, err.Error())
  137. return
  138. }
  139. _, loaded := s.userManager.Get(userName)
  140. if !loaded {
  141. writer.WriteHeader(http.StatusNotFound)
  142. return
  143. }
  144. err = s.userManager.Update(userName, updateRequest.Password)
  145. if err != nil {
  146. render.Status(request, http.StatusBadRequest)
  147. render.PlainText(writer, request, err.Error())
  148. return
  149. }
  150. writer.WriteHeader(http.StatusNoContent)
  151. }
  152. func (s *Server) deleteUser(writer http.ResponseWriter, request *http.Request) {
  153. userName := chi.URLParam(request, "username")
  154. if userName == "" {
  155. writer.WriteHeader(http.StatusBadRequest)
  156. return
  157. }
  158. _, loaded := s.userManager.Get(userName)
  159. if !loaded {
  160. writer.WriteHeader(http.StatusNotFound)
  161. return
  162. }
  163. err := s.userManager.Delete(userName)
  164. if err != nil {
  165. render.Status(request, http.StatusBadRequest)
  166. render.PlainText(writer, request, err.Error())
  167. return
  168. }
  169. writer.WriteHeader(http.StatusNoContent)
  170. }
  171. func (s *Server) getStats(writer http.ResponseWriter, request *http.Request) {
  172. requireClear := chi.URLParam(request, "clear") == "true"
  173. users := s.userManager.List()
  174. s.trafficManager.ReadUsers(users)
  175. for i := range users {
  176. users[i].Password = ""
  177. }
  178. uplinkBytes, downlinkBytes, uplinkPackets, downlinkPackets, tcpSessions, udpSessions := s.trafficManager.ReadGlobal()
  179. if requireClear {
  180. s.trafficManager.Clear()
  181. }
  182. render.JSON(writer, request, render.M{
  183. "uplinkBytes": uplinkBytes,
  184. "downlinkBytes": downlinkBytes,
  185. "uplinkPackets": uplinkPackets,
  186. "downlinkPackets": downlinkPackets,
  187. "tcpSessions": tcpSessions,
  188. "udpSessions": udpSessions,
  189. "users": users,
  190. })
  191. }