mirror of
https://github.com/portainer/portainer.git
synced 2025-07-23 15:29:42 +02:00
refactor(api): API overhaul (#392)
This commit is contained in:
parent
d9f6124609
commit
0a38bba874
36 changed files with 1275 additions and 869 deletions
247
api/http/user_handler.go
Normal file
247
api/http/user_handler.go
Normal file
|
@ -0,0 +1,247 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"github.com/portainer/portainer"
|
||||
|
||||
"encoding/json"
|
||||
"github.com/asaskevich/govalidator"
|
||||
"github.com/gorilla/mux"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
// UserHandler represents an HTTP API handler for managing users.
|
||||
type UserHandler struct {
|
||||
*mux.Router
|
||||
Logger *log.Logger
|
||||
UserService portainer.UserService
|
||||
CryptoService portainer.CryptoService
|
||||
middleWareService *middleWareService
|
||||
}
|
||||
|
||||
// NewUserHandler returns a new instance of UserHandler.
|
||||
func NewUserHandler(middleWareService *middleWareService) *UserHandler {
|
||||
h := &UserHandler{
|
||||
Router: mux.NewRouter(),
|
||||
Logger: log.New(os.Stderr, "", log.LstdFlags),
|
||||
middleWareService: middleWareService,
|
||||
}
|
||||
h.Handle("/users", middleWareService.addMiddleWares(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h.handlePostUsers(w, r)
|
||||
})))
|
||||
h.Handle("/users/{username}", middleWareService.addMiddleWares(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h.handleGetUser(w, r)
|
||||
}))).Methods("GET")
|
||||
h.Handle("/users/{username}", middleWareService.addMiddleWares(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h.handlePutUser(w, r)
|
||||
}))).Methods("PUT")
|
||||
h.Handle("/users/{username}/passwd", middleWareService.addMiddleWares(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h.handlePostUserPasswd(w, r)
|
||||
})))
|
||||
h.HandleFunc("/users/admin/check", h.handleGetAdminCheck)
|
||||
h.HandleFunc("/users/admin/init", h.handlePostAdminInit)
|
||||
return h
|
||||
}
|
||||
|
||||
// handlePostUsers handles POST requests on /users
|
||||
func (handler *UserHandler) handlePostUsers(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
handleNotAllowed(w, []string{"POST"})
|
||||
return
|
||||
}
|
||||
|
||||
var req postUsersRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
Error(w, ErrInvalidJSON, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(req)
|
||||
if err != nil {
|
||||
Error(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
user := &portainer.User{
|
||||
Username: req.Username,
|
||||
}
|
||||
user.Password, err = handler.CryptoService.Hash(req.Password)
|
||||
if err != nil {
|
||||
Error(w, portainer.ErrCryptoHashFailure, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
err = handler.UserService.UpdateUser(user)
|
||||
if err != nil {
|
||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type postUsersRequest struct {
|
||||
Username string `valid:"alphanum,required"`
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
// handlePostUserPasswd handles POST requests on /users/:username/passwd
|
||||
func (handler *UserHandler) handlePostUserPasswd(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
handleNotAllowed(w, []string{"POST"})
|
||||
return
|
||||
}
|
||||
|
||||
vars := mux.Vars(r)
|
||||
username := vars["username"]
|
||||
|
||||
var req postUserPasswdRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
Error(w, ErrInvalidJSON, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(req)
|
||||
if err != nil {
|
||||
Error(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
var password = req.Password
|
||||
|
||||
u, err := handler.UserService.User(username)
|
||||
if err == portainer.ErrUserNotFound {
|
||||
Error(w, err, http.StatusNotFound, handler.Logger)
|
||||
return
|
||||
} else if err != nil {
|
||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
valid := true
|
||||
err = handler.CryptoService.CompareHashAndData(u.Password, password)
|
||||
if err != nil {
|
||||
valid = false
|
||||
}
|
||||
|
||||
encodeJSON(w, &postUserPasswdResponse{Valid: valid}, handler.Logger)
|
||||
}
|
||||
|
||||
type postUserPasswdRequest struct {
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
type postUserPasswdResponse struct {
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
// handleGetUser handles GET requests on /users/:username
|
||||
func (handler *UserHandler) handleGetUser(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
username := vars["username"]
|
||||
|
||||
user, err := handler.UserService.User(username)
|
||||
if err == portainer.ErrUserNotFound {
|
||||
Error(w, err, http.StatusNotFound, handler.Logger)
|
||||
return
|
||||
} else if err != nil {
|
||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
user.Password = ""
|
||||
encodeJSON(w, &user, handler.Logger)
|
||||
}
|
||||
|
||||
// handlePutUser handles PUT requests on /users/:username
|
||||
func (handler *UserHandler) handlePutUser(w http.ResponseWriter, r *http.Request) {
|
||||
var req putUserRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
Error(w, ErrInvalidJSON, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(req)
|
||||
if err != nil {
|
||||
Error(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
user := &portainer.User{
|
||||
Username: req.Username,
|
||||
}
|
||||
user.Password, err = handler.CryptoService.Hash(req.Password)
|
||||
if err != nil {
|
||||
Error(w, portainer.ErrCryptoHashFailure, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
err = handler.UserService.UpdateUser(user)
|
||||
if err != nil {
|
||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type putUserRequest struct {
|
||||
Username string `valid:"alphanum,required"`
|
||||
Password string `valid:"required"`
|
||||
}
|
||||
|
||||
// handlePostAdminInit handles GET requests on /users/admin/check
|
||||
func (handler *UserHandler) handleGetAdminCheck(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
handleNotAllowed(w, []string{"GET"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := handler.UserService.User("admin")
|
||||
if err == portainer.ErrUserNotFound {
|
||||
Error(w, err, http.StatusNotFound, handler.Logger)
|
||||
return
|
||||
} else if err != nil {
|
||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
user.Password = ""
|
||||
encodeJSON(w, &user, handler.Logger)
|
||||
}
|
||||
|
||||
// handlePostAdminInit handles POST requests on /users/admin/init
|
||||
func (handler *UserHandler) handlePostAdminInit(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
handleNotAllowed(w, []string{"POST"})
|
||||
return
|
||||
}
|
||||
|
||||
var req postAdminInitRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
Error(w, ErrInvalidJSON, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
_, err := govalidator.ValidateStruct(req)
|
||||
if err != nil {
|
||||
Error(w, ErrInvalidRequestFormat, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
user := &portainer.User{
|
||||
Username: "admin",
|
||||
}
|
||||
user.Password, err = handler.CryptoService.Hash(req.Password)
|
||||
if err != nil {
|
||||
Error(w, portainer.ErrCryptoHashFailure, http.StatusBadRequest, handler.Logger)
|
||||
return
|
||||
}
|
||||
|
||||
err = handler.UserService.UpdateUser(user)
|
||||
if err != nil {
|
||||
Error(w, err, http.StatusInternalServerError, handler.Logger)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type postAdminInitRequest struct {
|
||||
Password string `valid:"required"`
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue