From c6b282fbcc9f7aebf78369874e718e7ef12fe9c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Thu, 20 Jan 2022 03:22:18 +0100 Subject: [PATCH] Add user create --- cmd/client/client.go | 59 ++++++++++++++++++++++++++++++++++++++++++++ http.go | 40 ++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) diff --git a/cmd/client/client.go b/cmd/client/client.go index c805dd1..02dd944 100644 --- a/cmd/client/client.go +++ b/cmd/client/client.go @@ -13,6 +13,7 @@ import ( "syscall" "time" + "git.t-juice.club/torjus/gpaste" "github.com/google/uuid" "github.com/urfave/cli/v2" "golang.org/x/term" @@ -53,6 +54,18 @@ func main() { ArgsUsage: "USERNAME", Action: ActionLogin, }, + { + Name: "admin", + Usage: "Admin related commands", + Subcommands: []*cli.Command{ + { + Name: "create-user", + Usage: "Create a new user", + ArgsUsage: "USERNAME", + Action: ActionUserCreate, + }, + }, + }, }, } @@ -170,6 +183,52 @@ func ActionLogin(c *cli.Context) error { return nil } +func ActionUserCreate(c *cli.Context) error { + // TODO: Needs to supply auth token to actually work + username := c.Args().First() + if username == "" { + return cli.Exit("USERNAME not supplied.", 1) + } + password, err := readPassword() + if err != nil { + return fmt.Errorf("error reading password: %w", err) + } + + url := fmt.Sprintf("%s/api/user", c.String("url")) + client := &http.Client{} + // TODO: Change timeout + ctx, cancel := context.WithTimeout(c.Context, 10*time.Second) + defer cancel() + + body := new(bytes.Buffer) + requestData := &gpaste.RequestAPIUserCreate{ + Username: username, + Password: password, + } + encoder := json.NewEncoder(body) + if err := encoder.Encode(requestData); err != nil { + return fmt.Errorf("error encoding response: %w", err) + } + req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body) + if err != nil { + return fmt.Errorf("error creating request: %w", err) + } + + resp, err := client.Do(req) + if err != nil { + return fmt.Errorf("unable to perform request: %s", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusAccepted { + return cli.Exit("got non-ok response from server", 0) + } + + fmt.Printf("Created user %s\n", username) + + return nil +} + func readPassword() (string, error) { fmt.Print("Enter Password: ") bytePassword, err := term.ReadPassword(int(syscall.Stdin)) diff --git a/http.go b/http.go index 85c64dc..e61351a 100644 --- a/http.go +++ b/http.go @@ -47,6 +47,7 @@ func NewHTTPServer(cfg *ServerConfig) *HTTPServer { r.Post("/api/file", srv.HandlerAPIFilePost) r.Get("/api/file/{id}", srv.HandlerAPIFileGet) r.Post("/api/login", srv.HandlerAPILogin) + r.Post("/api/user", srv.HandlerAPIUserCreate) srv.Handler = r return srv @@ -188,3 +189,42 @@ func (s *HTTPServer) HandlerAPILogin(w http.ResponseWriter, r *http.Request) { s.Logger.Infow("Error encoding json response to client.", "req_id", reqID, "error", err, "remote_addr", r.RemoteAddr) } } + +type RequestAPIUserCreate struct { + Username string `json:"username"` + Password string `json:"password"` +} + +func (s *HTTPServer) HandlerAPIUserCreate(w http.ResponseWriter, r *http.Request) { + reqID := middleware.GetReqID(r.Context()) + defer r.Body.Close() + + level, err := AuthLevelFromRequest(r) + if err != nil || level < AuthLevelAdmin { + 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 + user := &User{Username: req.Username} + 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 + } + s.Logger.Infow("Created user.", "req_id", reqID, "remote_addr", r.RemoteAddr, "username", req.Username) +}