gpaste/api/http.go

254 lines
7.3 KiB
Go
Raw Normal View History

2022-01-20 02:44:33 +00:00
package api
2022-01-15 20:53:22 +00:00
import (
"encoding/json"
"io"
"net/http"
2022-01-16 20:29:42 +00:00
"strings"
2022-01-15 20:53:22 +00:00
2022-01-20 02:44:33 +00:00
"git.t-juice.club/torjus/gpaste"
2022-01-20 02:40:32 +00:00
"git.t-juice.club/torjus/gpaste/files"
2022-01-20 02:35:55 +00:00
"git.t-juice.club/torjus/gpaste/users"
2022-01-15 20:53:22 +00:00
"github.com/go-chi/chi/v5"
2022-01-19 02:23:54 +00:00
"github.com/go-chi/chi/v5/middleware"
2022-01-15 20:53:22 +00:00
"github.com/google/uuid"
2022-01-15 21:32:24 +00:00
"go.uber.org/zap"
2022-01-15 20:53:22 +00:00
)
type HTTPServer struct {
2022-01-20 02:40:32 +00:00
Files files.FileStore
2022-01-20 02:35:55 +00:00
Users users.UserStore
2022-01-20 02:44:33 +00:00
Auth *gpaste.AuthService
config *gpaste.ServerConfig
2022-01-19 02:23:54 +00:00
Logger *zap.SugaredLogger
AccessLogger *zap.SugaredLogger
2022-01-15 20:53:22 +00:00
http.Server
}
2022-01-20 02:44:33 +00:00
func NewHTTPServer(cfg *gpaste.ServerConfig) *HTTPServer {
2022-01-15 20:53:22 +00:00
srv := &HTTPServer{
2022-01-19 02:23:54 +00:00
config: cfg,
Logger: zap.NewNop().Sugar(),
AccessLogger: zap.NewNop().Sugar(),
2022-01-15 20:53:22 +00:00
}
2022-01-20 02:40:32 +00:00
srv.Files = files.NewMemoryFileStore()
2022-01-20 02:35:55 +00:00
srv.Users = users.NewMemoryUserStore()
2022-01-20 02:44:33 +00:00
srv.Auth = gpaste.NewAuthService(srv.Users, []byte(srv.config.SigningSecret))
2022-01-15 20:53:22 +00:00
2022-01-19 21:44:00 +00:00
// Create initial user
// TODO: Do properly
2022-01-20 22:31:09 +00:00
user := &users.User{Username: "admin", Role: users.RoleAdmin}
2022-01-19 21:44:00 +00:00
user.SetPassword("admin")
srv.Users.Store(user)
2022-01-15 20:53:22 +00:00
r := chi.NewRouter()
2022-01-19 02:23:54 +00:00
r.Use(middleware.RealIP)
r.Use(middleware.RequestID)
r.Use(srv.MiddlewareAccessLogger)
2022-01-20 00:04:44 +00:00
r.Use(srv.MiddlewareAuthentication)
2022-01-15 20:53:22 +00:00
r.Get("/", srv.HandlerIndex)
r.Post("/api/file", srv.HandlerAPIFilePost)
r.Get("/api/file/{id}", srv.HandlerAPIFileGet)
2022-01-21 06:17:52 +00:00
r.Delete("/api/file/{id}", srv.HandlerAPIFileDelete)
2022-01-19 21:25:19 +00:00
r.Post("/api/login", srv.HandlerAPILogin)
2022-01-20 02:22:18 +00:00
r.Post("/api/user", srv.HandlerAPIUserCreate)
2022-01-15 20:53:22 +00:00
srv.Handler = r
return srv
}
func (s *HTTPServer) HandlerIndex(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write([]byte("index"))
}
func (s *HTTPServer) HandlerAPIFilePost(w http.ResponseWriter, r *http.Request) {
2022-01-20 02:40:32 +00:00
f := &files.File{
2022-01-15 20:53:22 +00:00
ID: uuid.Must(uuid.NewRandom()).String(),
Body: r.Body,
}
2022-01-19 02:23:54 +00:00
reqID := middleware.GetReqID(r.Context())
2022-01-15 20:53:22 +00:00
2022-01-16 20:29:42 +00:00
// Check if multipart form
ct := r.Header.Get("Content-Type")
if strings.Contains(ct, "multipart/form-data") {
s.processMultiPartFormUpload(w, r)
return
}
2022-01-19 21:25:19 +00:00
err := s.Files.Store(f)
2022-01-15 20:53:22 +00:00
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
2022-01-19 02:23:54 +00:00
s.Logger.Warnw("Error storing file.", "req_id", reqID, "error", err, "id", f.ID, "remote_addr", r.RemoteAddr)
2022-01-15 20:53:22 +00:00
return
}
2022-01-19 02:23:54 +00:00
s.Logger.Infow("Stored file.", "req_id", reqID, "id", f.ID, "remote_addr", r.RemoteAddr)
2022-01-15 20:53:22 +00:00
var resp = struct {
Message string `json:"message"`
ID string `json:"id"`
URL string `json:"url"`
}{
Message: "OK",
ID: f.ID,
URL: "TODO",
}
w.WriteHeader(http.StatusAccepted)
encoder := json.NewEncoder(w)
if err := encoder.Encode(&resp); err != nil {
2022-01-19 02:23:54 +00:00
s.Logger.Warnw("Error encoding response to client.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr)
2022-01-15 20:53:22 +00:00
}
}
func (s *HTTPServer) HandlerAPIFileGet(w http.ResponseWriter, r *http.Request) {
id := chi.URLParam(r, "id")
if id == "" {
w.WriteHeader(http.StatusBadRequest)
return
}
2022-01-19 21:25:19 +00:00
f, err := s.Files.Get(id)
2022-01-15 20:53:22 +00:00
if err != nil {
// TODO: LOG
w.WriteHeader(http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusOK)
if _, err := io.Copy(w, f.Body); err != nil {
2022-01-19 02:23:54 +00:00
reqID := middleware.GetReqID(r.Context())
s.Logger.Warnw("Error writing file to client.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr)
2022-01-15 20:53:22 +00:00
}
}
2022-01-16 20:29:42 +00:00
2022-01-21 06:17:52 +00:00
func (s *HTTPServer) HandlerAPIFileDelete(w http.ResponseWriter, r *http.Request) {
// TODO: Require auth
id := chi.URLParam(r, "id")
if id == "" {
w.WriteHeader(http.StatusBadRequest)
return
}
err := s.Files.Delete(id)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
reqID := middleware.GetReqID(r.Context())
s.Logger.Infow("Deleted file", "id", id, "req_id", reqID)
}
2022-01-16 20:29:42 +00:00
func (s *HTTPServer) processMultiPartFormUpload(w http.ResponseWriter, r *http.Request) {
2022-01-19 02:23:54 +00:00
reqID := middleware.GetReqID(r.Context())
2022-01-16 20:29:42 +00:00
2022-01-20 16:50:56 +00:00
var responses []ResponseAPIFilePost
2022-01-16 20:29:42 +00:00
if err := r.ParseMultipartForm(1024 * 1024 * 10); err != nil {
2022-01-19 02:23:54 +00:00
s.Logger.Warnw("Error parsing multipart form.", "req_id", reqID, "err", err)
2022-01-16 20:29:42 +00:00
}
for k := range r.MultipartForm.File {
ff, fh, err := r.FormFile(k)
if err != nil {
2022-01-19 02:23:54 +00:00
s.Logger.Warnw("Error reading file from multipart form.", "req_id", reqID, "error", err)
2022-01-16 20:29:42 +00:00
return
}
2022-01-20 02:40:32 +00:00
f := &files.File{
2022-01-16 20:29:42 +00:00
ID: uuid.Must(uuid.NewRandom()).String(),
OriginalFilename: fh.Filename,
Body: ff,
}
2022-01-19 21:25:19 +00:00
if err := s.Files.Store(f); err != nil {
2022-01-16 20:29:42 +00:00
w.WriteHeader(http.StatusInternalServerError)
2022-01-19 02:23:54 +00:00
s.Logger.Warnw("Error storing file.", "req_id", reqID, "error", err, "id", f.ID, "remote_addr", r.RemoteAddr)
2022-01-16 20:29:42 +00:00
return
}
2022-01-19 02:23:54 +00:00
s.Logger.Infow("Stored file.", "req_id", reqID, "id", f.ID, "filename", f.OriginalFilename, "remote_addr", r.RemoteAddr)
2022-01-16 20:29:42 +00:00
2022-01-20 16:50:56 +00:00
responses = append(responses, ResponseAPIFilePost{Message: "OK", ID: f.ID, URL: "TODO"})
2022-01-16 20:29:42 +00:00
}
w.WriteHeader(http.StatusAccepted)
encoder := json.NewEncoder(w)
if err := encoder.Encode(&responses); err != nil {
2022-01-19 02:23:54 +00:00
s.Logger.Warnw("Error encoding response to client.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr)
2022-01-16 20:29:42 +00:00
}
}
2022-01-19 21:25:19 +00:00
func (s *HTTPServer) HandlerAPILogin(w http.ResponseWriter, r *http.Request) {
reqID := middleware.GetReqID(r.Context())
2022-01-20 16:50:56 +00:00
var expectedRequest RequestAPILogin
2022-01-19 21:25:19 +00:00
decoder := json.NewDecoder(r.Body)
defer r.Body.Close()
if err := decoder.Decode(&expectedRequest); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
token, err := s.Auth.Login(expectedRequest.Username, expectedRequest.Password)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
2022-01-20 16:50:56 +00:00
response := ResponseAPILogin{
2022-01-19 21:25:19 +00:00
Token: token,
}
2022-01-19 21:44:00 +00:00
s.Logger.Infow("User logged in.", "req_id", reqID, "username", expectedRequest.Username)
2022-01-19 21:25:19 +00:00
encoder := json.NewEncoder(w)
if err := encoder.Encode(&response); err != nil {
s.Logger.Infow("Error encoding json response to client.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr)
}
}
2022-01-20 02:22:18 +00:00
func (s *HTTPServer) HandlerAPIUserCreate(w http.ResponseWriter, r *http.Request) {
reqID := middleware.GetReqID(r.Context())
defer r.Body.Close()
2022-01-20 16:50:56 +00:00
role, err := RoleFromRequest(r)
if err != nil || role != users.RoleAdmin {
2022-01-20 02:22:18 +00:00
w.WriteHeader(http.StatusUnauthorized)
return
}
var req RequestAPIUserCreate
decoder := json.NewDecoder(r.Body)
if err := decoder.Decode(&req); err != nil {
s.Logger.Debugw("Error parsing request.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr)
w.WriteHeader(http.StatusBadRequest)
return
}
// TODO: Ensure user does not already exist
2022-01-22 09:19:18 +00:00
user := &users.User{Username: req.Username, Role: users.RoleUser}
2022-01-20 02:22:18 +00:00
if err := user.SetPassword(req.Password); err != nil {
s.Logger.Warnw("Error setting user password.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr)
w.WriteHeader(http.StatusBadRequest)
return
}
if err := s.Users.Store(user); err != nil {
s.Logger.Warnw("Error setting user password.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr)
w.WriteHeader(http.StatusInternalServerError)
return
}
2022-01-20 16:50:56 +00:00
w.WriteHeader(http.StatusAccepted)
2022-01-20 02:22:18 +00:00
s.Logger.Infow("Created user.", "req_id", reqID, "remote_addr", r.RemoteAddr, "username", req.Username)
}
2022-01-21 13:11:47 +00:00
func (s *HTTPServer) HandlerAPIUserList(w http.ResponseWriter, r *http.Request) {
reqID := middleware.GetReqID(r.Context())
l, err := s.Users.List()
if err != nil {
s.Logger.Warnw("Error listing users.", "req_id", reqID, "error", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
encoder := json.NewEncoder(w)
if err := encoder.Encode(l); err != nil {
s.Logger.Warnw("Error encoding response.", "req_id", "error", err)
}
}