358 lines
8.1 KiB
Go
358 lines
8.1 KiB
Go
package shared
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"time"
|
|
|
|
"git.markbailey.dev/cerbervs/ptpp/app/controller"
|
|
"git.markbailey.dev/cerbervs/ptpp/app/session"
|
|
"git.markbailey.dev/cerbervs/ptpp/lib/database"
|
|
"git.markbailey.dev/cerbervs/ptpp/lib/database/dto"
|
|
"git.markbailey.dev/cerbervs/ptpp/lib/logger"
|
|
"git.markbailey.dev/cerbervs/ptpp/util"
|
|
|
|
"git.markbailey.dev/cerbervs/ptpp/view/user"
|
|
)
|
|
|
|
type SignUpHandler struct {
|
|
controller.Controller
|
|
}
|
|
|
|
func (c SignUpHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) controller.IController {
|
|
c.Logger = l
|
|
c.Db = d
|
|
c.Session = s
|
|
|
|
return c
|
|
}
|
|
|
|
type SignInHandler struct {
|
|
controller.Controller
|
|
}
|
|
|
|
func (c SignInHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) controller.IController {
|
|
c.Logger = l
|
|
c.Db = d
|
|
c.Session = s
|
|
|
|
return c
|
|
}
|
|
|
|
type PopulateHandler struct {
|
|
controller.Controller
|
|
}
|
|
|
|
func (c PopulateHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) controller.IController {
|
|
c.Logger = l
|
|
c.Db = d
|
|
c.Session = s
|
|
|
|
return c
|
|
}
|
|
|
|
type SignOutHandler struct {
|
|
controller.Controller
|
|
}
|
|
|
|
func (c SignOutHandler) Init(s session.IManager, d database.IDB, l logger.ILogger) controller.IController {
|
|
c.Logger = l
|
|
c.Db = d
|
|
c.Session = s
|
|
|
|
return c
|
|
}
|
|
|
|
func (c PopulateHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
existingOrg, err := c.Db.Repo().FindOrganizationByName("CerbervsSoft")
|
|
if existingOrg != nil && err == nil {
|
|
return util.Redirect(w, r, "/signup", http.StatusSeeOther, false)
|
|
}
|
|
|
|
authToken, err := util.CreateTokenForUser("CerbervsSoft")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
organization := dto.Organization{
|
|
Name: "CerbervsSoft",
|
|
OwnerName: "Mark Bailey",
|
|
OwnerEmail: "email@provider.com",
|
|
OwnerPhone: "+11111111111",
|
|
Authorized: 1,
|
|
AuthToken: authToken,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
_, err = c.Db.Repo().CreateOrganization(organization)
|
|
if err != nil {
|
|
c.Db.Error(err)
|
|
return err
|
|
}
|
|
|
|
return util.Redirect(w, r, "/signup", http.StatusSeeOther, false)
|
|
}
|
|
|
|
type UserSignInForm struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
func (c SignInHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
sess := c.Session.SessionStart(w, r)
|
|
|
|
username, ok := r.Context().Value("username").(string)
|
|
if ok {
|
|
if username == "" {
|
|
return failWithFormError(w, r, "Invalid Username or Password.", sess)
|
|
} else {
|
|
foundUser, err := c.Db.Repo().FindUserByUsername(username)
|
|
if foundUser == nil || err != nil {
|
|
return failWithFormError(w, r, "Invalid Username or Password.", sess)
|
|
}
|
|
|
|
if foundUser.Admin == 1 {
|
|
return util.Redirect(w, r, "/admin/", http.StatusSeeOther, false)
|
|
} else {
|
|
return util.Redirect(w, r, "/", http.StatusSeeOther, false)
|
|
}
|
|
}
|
|
}
|
|
|
|
formError, ok := sess.Get("formError").(string)
|
|
if !ok {
|
|
formError = ""
|
|
}
|
|
|
|
if err := user.SignIn(formError).Render(context.Background(), w); err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error rendering sign in form"))
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c SignInHandler) Post(w http.ResponseWriter, r *http.Request) error {
|
|
sess := c.Session.SessionStart(w, r)
|
|
|
|
fd := &UserSignInForm{}
|
|
|
|
jsonDecoder := json.NewDecoder(r.Body)
|
|
if err := jsonDecoder.Decode(&fd); err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error decoding JSON"))
|
|
return err
|
|
}
|
|
|
|
foundUser, err := c.Db.Repo().FindUserByUsername(fd.Username)
|
|
if foundUser == nil || err != nil {
|
|
return util.Redirect(w, r, "/sign-in", http.StatusPermanentRedirect, false)
|
|
}
|
|
|
|
authenticated, err := util.CheckPassword(fd.Password, foundUser.Password)
|
|
if err != nil || !authenticated {
|
|
return failWithFormError(w, r, "Invalid Username or Password.", sess)
|
|
}
|
|
|
|
err = sess.Set("username", foundUser.Username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
token, err := util.CreateTokenForUser(foundUser.Username)
|
|
if err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error creating token"))
|
|
return err
|
|
}
|
|
|
|
err = sess.Set("token", token)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
authToken, err := util.CreateTokenForUser(foundUser.Username)
|
|
if err != nil {
|
|
c.Logger.Error(err)
|
|
return err
|
|
}
|
|
|
|
_, err = c.Db.Repo().CreateHeartbeat(&dto.Heartbeat{
|
|
User: foundUser.Identifier,
|
|
CreatedAt: time.Now(),
|
|
IpAddr: r.RemoteAddr,
|
|
AuthToken: authToken,
|
|
})
|
|
if err != nil {
|
|
c.Db.Error(err)
|
|
return err
|
|
}
|
|
|
|
jwtToken, err := util.CreateTokenForUser(fd.Username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "token",
|
|
Value: jwtToken,
|
|
Expires: time.Now().Add(time.Hour * 1),
|
|
Path: "/",
|
|
})
|
|
|
|
err = sess.Delete("formError")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
c.Logger.Info(foundUser.Username + " logged in")
|
|
if foundUser.Admin == 1 {
|
|
return util.Redirect(w, r, "/admin/", http.StatusSeeOther, false)
|
|
} else {
|
|
return util.Redirect(w, r, "/", http.StatusSeeOther, false)
|
|
}
|
|
}
|
|
|
|
type UserSignUpForm struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
PasswordConfirmation string `json:"password_confirmation"`
|
|
}
|
|
|
|
func (c SignUpHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
sess := c.Session.SessionStart(w, r)
|
|
|
|
uname, ok := sess.Get("username").(string)
|
|
if !ok {
|
|
uname = ""
|
|
}
|
|
if uname != "" {
|
|
return util.Redirect(w, r, "/", http.StatusSeeOther, false)
|
|
}
|
|
|
|
if err := user.SignUpForm().Render(context.Background(), w); err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error rendering sign up form"))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c SignUpHandler) Post(w http.ResponseWriter, r *http.Request) error {
|
|
fd := &UserSignUpForm{}
|
|
|
|
jsonDecoder := json.NewDecoder(r.Body)
|
|
if err := jsonDecoder.Decode(&fd); err == nil {
|
|
if fd.Password != fd.PasswordConfirmation {
|
|
if _, err := w.Write([]byte("Passwords don't match")); err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
foundUser, err := c.Db.Repo().FindUserByUsername(fd.Username)
|
|
if err != nil {
|
|
c.Db.Error(err)
|
|
return err
|
|
}
|
|
|
|
if foundUser != nil {
|
|
if _, err := w.Write([]byte("Invalid username. Please try another")); err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error writing response"))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
token, err := util.CreateTokenForUser(fd.Username)
|
|
if err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error creating token"))
|
|
return err
|
|
}
|
|
|
|
password, err := util.HashPassword(fd.PasswordConfirmation)
|
|
if err != nil {
|
|
c.Logger.Error(c.Logger.Wrap(err, "Error hashing password"))
|
|
return err
|
|
}
|
|
|
|
org, err := c.Db.Repo().FindOrganizationByName("CerbervsSoft")
|
|
if org == nil || err != nil {
|
|
c.Db.Error(err)
|
|
return err
|
|
}
|
|
|
|
newUser, err := c.Db.Repo().CreateUser(dto.User{
|
|
Username: fd.Username,
|
|
Password: password,
|
|
Name: fd.Name,
|
|
Email: fd.Email,
|
|
AuthToken: token,
|
|
Authorized: 1,
|
|
Admin: 1,
|
|
Organization: org.Identifier,
|
|
})
|
|
if err != nil {
|
|
c.Db.Error(err)
|
|
return err
|
|
}
|
|
|
|
_, err = c.Db.Repo().CreateHeartbeat(&dto.Heartbeat{
|
|
User: newUser.Identifier,
|
|
CreatedAt: time.Now(),
|
|
IpAddr: r.RemoteAddr,
|
|
AuthToken: token,
|
|
})
|
|
if err != nil {
|
|
c.Db.Error(err)
|
|
return err
|
|
}
|
|
|
|
jwtToken, err := util.CreateTokenForUser(fd.Username)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "token",
|
|
Value: jwtToken,
|
|
Expires: time.Now().Add(time.Hour * 1),
|
|
Path: "/",
|
|
})
|
|
|
|
return util.Redirect(w, r, "/sign-in", http.StatusSeeOther, false)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c SignOutHandler) Get(w http.ResponseWriter, r *http.Request) error {
|
|
sess := c.Session.SessionStart(w, r)
|
|
|
|
err := sess.Delete("username")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = sess.Delete("token")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "token",
|
|
Value: "",
|
|
Expires: time.Now().Add(-time.Hour),
|
|
Path: "/",
|
|
})
|
|
|
|
return util.Redirect(w, r, "/", http.StatusSeeOther, true)
|
|
}
|
|
|
|
func failWithFormError(w http.ResponseWriter, r *http.Request, formError string, sess session.ISession) error {
|
|
err := sess.Set("formError", formError)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return util.Redirect(w, r, r.URL.Path, http.StatusSeeOther, false)
|
|
}
|