Nashboard/handlers.go

127 lines
3.2 KiB
Go

package main
import (
"encoding/json"
"io"
"log"
"net/http"
"time"
"github.com/gorilla/mux"
"go.mongodb.org/mongo-driver/bson/primitive"
"golang.org/x/crypto/bcrypt"
)
type Server struct {
host string
mux *mux.Router
db Storage
}
var ErrUnauthorized ApiError = ApiError{Status: http.StatusUnauthorized, Err: "Unauthorized"}
var ErrBadRequest ApiError = ApiError{Status: http.StatusBadRequest, Err: "bad request"}
func (s Server) InitHandlers() {
r := s.mux
apiRouter := r.PathPrefix("/api").Subrouter()
authRouter := apiRouter.PathPrefix("/user").Subrouter()
me := authRouter.Path("/me").Subrouter()
me.Use(s.AuthorizedOnly)
me.Path("").HandlerFunc(MakeHTTPHandler(s.handleGetUser))
authRouter.Path("/reg").Methods("POST").HandlerFunc(MakeHTTPHandler(s.handleRegister))
authRouter.Path("/login").Methods("POST").HandlerFunc(MakeHTTPHandler(s.handleLogin))
r.PathPrefix("/").Handler(http.FileServer(http.Dir("./static/")))
}
var anon User = User{
Id: primitive.ObjectID{},
Username: "Anonymous",
IsAdmin: false,
}
func (s Server) handleGetUser(w http.ResponseWriter, r *http.Request) error {
ctx := r.Context()
user := ctx.Value(CtxUser("user")).(*User)
return WriteJSON(w, 200, user)
}
type registerForm struct {
Username string
Password string
}
func (s Server) handleRegister(w http.ResponseWriter, r *http.Request) error {
var form registerForm
err := DecodeJSON(r.Body, &form)
if err != nil {
return ApiError{Status: http.StatusBadRequest, Err: "bad credentials"}
}
password, err := bcrypt.GenerateFromPassword([]byte(form.Password), 0)
if err != nil {
log.Println("Can not generate hash from password: ", err)
return ApiError{Status: http.StatusInternalServerError, Err: "cannot register"}
}
newUser := User{
Id: primitive.NewObjectID(),
Username: form.Username,
Password: password,
IsAdmin: true,
}
if err = s.db.CreateUser(&newUser); err != nil {
log.Println("Can not create user: ", err)
return ApiError{Status: http.StatusInternalServerError, Err: "cannot register"}
}
return WriteJSON(w, http.StatusCreated, &newUser)
}
type loginForm struct {
Username string
Password string
}
func (s Server) handleLogin(w http.ResponseWriter, r *http.Request) error {
var form loginForm
err := DecodeJSON(r.Body, &form)
if err != nil {
log.Println("Can not decode json from login: ", err)
return ErrBadRequest
}
user, err := s.db.GetUserByName(form.Username)
if err != nil {
log.Println("Can not find user: ", err)
return ErrBadRequest
}
err = bcrypt.CompareHashAndPassword(user.Password, []byte(form.Password))
if err != nil {
log.Println("Can not compare password and hash: ", err)
return ErrBadRequest
}
ses := Session{
Id: primitive.NewObjectID(),
Token: GenSessionToken(),
UserID: user.Id,
LoggedAt: time.Now(),
IsAdmin: true,
ExpiresAt: time.Now().Add(42 * time.Hour * 24),
IP: r.RemoteAddr,
}
user.LastLogin = time.Now()
if err := s.db.UpdateUser(user); err != nil {
log.Println("Can not update user: ", err)
}
if err = s.db.CreateSession(&ses); err != nil {
log.Println("Can not store session: ", err)
return ErrBadRequest
}
return WriteJSON(w, 200, ses)
}
func DecodeJSON(r io.Reader, v any) error {
return json.NewDecoder(r).Decode(v)
}