api_admin.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. package httpd
  2. import (
  3. "context"
  4. "errors"
  5. "net/http"
  6. "strconv"
  7. "github.com/go-chi/jwtauth"
  8. "github.com/go-chi/render"
  9. "github.com/drakkan/sftpgo/dataprovider"
  10. )
  11. type adminPwd struct {
  12. CurrentPassword string `json:"current_password"`
  13. NewPassword string `json:"new_password"`
  14. }
  15. func getAdmins(w http.ResponseWriter, r *http.Request) {
  16. limit := 100
  17. offset := 0
  18. order := dataprovider.OrderASC
  19. var err error
  20. if _, ok := r.URL.Query()["limit"]; ok {
  21. limit, err = strconv.Atoi(r.URL.Query().Get("limit"))
  22. if err != nil {
  23. err = errors.New("Invalid limit")
  24. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  25. return
  26. }
  27. if limit > 500 {
  28. limit = 500
  29. }
  30. }
  31. if _, ok := r.URL.Query()["offset"]; ok {
  32. offset, err = strconv.Atoi(r.URL.Query().Get("offset"))
  33. if err != nil {
  34. err = errors.New("Invalid offset")
  35. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  36. return
  37. }
  38. }
  39. if _, ok := r.URL.Query()["order"]; ok {
  40. order = r.URL.Query().Get("order")
  41. if order != dataprovider.OrderASC && order != dataprovider.OrderDESC {
  42. err = errors.New("Invalid order")
  43. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  44. return
  45. }
  46. }
  47. admins, err := dataprovider.GetAdmins(limit, offset, order)
  48. if err != nil {
  49. sendAPIResponse(w, r, err, "", getRespStatus(err))
  50. return
  51. }
  52. render.JSON(w, r, admins)
  53. }
  54. func getAdminByUsername(w http.ResponseWriter, r *http.Request) {
  55. username := getURLParam(r, "username")
  56. renderAdmin(w, r, username, http.StatusOK)
  57. }
  58. func renderAdmin(w http.ResponseWriter, r *http.Request, username string, status int) {
  59. admin, err := dataprovider.AdminExists(username)
  60. if err != nil {
  61. sendAPIResponse(w, r, err, "", getRespStatus(err))
  62. return
  63. }
  64. admin.HideConfidentialData()
  65. if status != http.StatusOK {
  66. ctx := context.WithValue(r.Context(), render.StatusCtxKey, http.StatusCreated)
  67. render.JSON(w, r.WithContext(ctx), admin)
  68. } else {
  69. render.JSON(w, r, admin)
  70. }
  71. }
  72. func addAdmin(w http.ResponseWriter, r *http.Request) {
  73. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  74. var admin dataprovider.Admin
  75. err := render.DecodeJSON(r.Body, &admin)
  76. if err != nil {
  77. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  78. return
  79. }
  80. err = dataprovider.AddAdmin(&admin)
  81. if err != nil {
  82. sendAPIResponse(w, r, err, "", getRespStatus(err))
  83. return
  84. }
  85. renderAdmin(w, r, admin.Username, http.StatusCreated)
  86. }
  87. func updateAdmin(w http.ResponseWriter, r *http.Request) {
  88. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  89. username := getURLParam(r, "username")
  90. admin, err := dataprovider.AdminExists(username)
  91. if err != nil {
  92. sendAPIResponse(w, r, err, "", getRespStatus(err))
  93. return
  94. }
  95. adminID := admin.ID
  96. err = render.DecodeJSON(r.Body, &admin)
  97. if err != nil {
  98. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  99. return
  100. }
  101. claims, err := getTokenClaims(r)
  102. if err != nil || claims.Username == "" {
  103. sendAPIResponse(w, r, err, "Invalid token claims", http.StatusBadRequest)
  104. return
  105. }
  106. if username == claims.Username {
  107. if claims.isCriticalPermRemoved(admin.Permissions) {
  108. sendAPIResponse(w, r, errors.New("You cannot remove these permissions to yourself"), "", http.StatusBadRequest)
  109. return
  110. }
  111. if admin.Status == 0 {
  112. sendAPIResponse(w, r, errors.New("You cannot disable yourself"), "", http.StatusBadRequest)
  113. return
  114. }
  115. }
  116. admin.ID = adminID
  117. admin.Username = username
  118. if err := dataprovider.UpdateAdmin(&admin); err != nil {
  119. sendAPIResponse(w, r, err, "", getRespStatus(err))
  120. return
  121. }
  122. sendAPIResponse(w, r, nil, "Admin updated", http.StatusOK)
  123. }
  124. func deleteAdmin(w http.ResponseWriter, r *http.Request) {
  125. username := getURLParam(r, "username")
  126. claims, err := getTokenClaims(r)
  127. if err != nil || claims.Username == "" {
  128. sendAPIResponse(w, r, err, "Invalid token claims", http.StatusBadRequest)
  129. return
  130. }
  131. if username == claims.Username {
  132. sendAPIResponse(w, r, errors.New("You cannot delete yourself"), "", http.StatusBadRequest)
  133. return
  134. }
  135. err = dataprovider.DeleteAdmin(username)
  136. if err != nil {
  137. sendAPIResponse(w, r, err, "", getRespStatus(err))
  138. return
  139. }
  140. sendAPIResponse(w, r, err, "Admin deleted", http.StatusOK)
  141. }
  142. func changeAdminPassword(w http.ResponseWriter, r *http.Request) {
  143. r.Body = http.MaxBytesReader(w, r.Body, maxRequestSize)
  144. var pwd adminPwd
  145. err := render.DecodeJSON(r.Body, &pwd)
  146. if err != nil {
  147. sendAPIResponse(w, r, err, "", http.StatusBadRequest)
  148. return
  149. }
  150. err = doChangeAdminPassword(r, pwd.CurrentPassword, pwd.NewPassword, pwd.NewPassword)
  151. if err != nil {
  152. sendAPIResponse(w, r, err, "", getRespStatus(err))
  153. return
  154. }
  155. sendAPIResponse(w, r, err, "Password updated", http.StatusOK)
  156. }
  157. func doChangeAdminPassword(r *http.Request, currentPassword, newPassword, confirmNewPassword string) error {
  158. if currentPassword == "" || newPassword == "" || confirmNewPassword == "" {
  159. return dataprovider.NewValidationError("Please provide the current password and the new one two times")
  160. }
  161. if newPassword != confirmNewPassword {
  162. return dataprovider.NewValidationError("The two password fields do not match")
  163. }
  164. if currentPassword == newPassword {
  165. return dataprovider.NewValidationError("The new password must be different from the current one")
  166. }
  167. claims, err := getTokenClaims(r)
  168. if err != nil {
  169. return err
  170. }
  171. admin, err := dataprovider.AdminExists(claims.Username)
  172. if err != nil {
  173. return err
  174. }
  175. match, err := admin.CheckPassword(currentPassword)
  176. if !match || err != nil {
  177. return dataprovider.NewValidationError("Current password does not match")
  178. }
  179. admin.Password = newPassword
  180. return dataprovider.UpdateAdmin(&admin)
  181. }
  182. func getTokenClaims(r *http.Request) (jwtTokenClaims, error) {
  183. tokenClaims := jwtTokenClaims{}
  184. _, claims, err := jwtauth.FromContext(r.Context())
  185. if err != nil {
  186. return tokenClaims, err
  187. }
  188. tokenClaims.Decode(claims)
  189. return tokenClaims, nil
  190. }