Auth fixes

This commit is contained in:
Atridad Lahiji 2024-06-28 09:11:03 -06:00
parent de07026042
commit 7978dd131a
No known key found for this signature in database
8 changed files with 52 additions and 13 deletions

View file

@ -8,15 +8,25 @@ import (
) )
func RegisterUserHandler(c echo.Context) error { func RegisterUserHandler(c echo.Context) error {
name := c.FormValue("name")
email := c.FormValue("email") email := c.FormValue("email")
password := c.FormValue("password") password := c.FormValue("password")
// Check if the email already exists
existingUser, err := lib.GetUserByEmail(lib.GetDBPool(), email)
if err == nil && existingUser != nil {
// User with the given email already exists
errorMessage := `<div id="error-message" style="color: red;">An account with this email already exists!</div>`
return c.HTML(http.StatusBadRequest, errorMessage)
}
// Proceed with the existing registration logic
hashedPassword, err := lib.HashPassword(password) hashedPassword, err := lib.HashPassword(password)
if err != nil { if err != nil {
return c.JSON(http.StatusInternalServerError, "Failed to hash password") return c.JSON(http.StatusInternalServerError, "Failed to hash password")
} }
user := lib.User{Email: email, Password: hashedPassword} user := lib.User{Name: name, Email: email, Password: hashedPassword}
if err := lib.SaveUser(lib.GetDBPool(), &user); err != nil { if err := lib.SaveUser(lib.GetDBPool(), &user); err != nil {
return c.JSON(http.StatusInternalServerError, "Failed to save user") return c.JSON(http.StatusInternalServerError, "Failed to save user")
} }
@ -30,6 +40,7 @@ func RegisterUserHandler(c echo.Context) error {
lib.SetSessionCookie(c.Response().Writer, "session", lib.SessionData{ lib.SetSessionCookie(c.Response().Writer, "session", lib.SessionData{
SessionID: sessionID, SessionID: sessionID,
UserID: user.ID, UserID: user.ID,
Name: user.Name,
Email: user.Email, Email: user.Email,
Roles: []string{"user"}, Roles: []string{"user"},
}) })

View file

@ -12,6 +12,7 @@ import (
type User struct { type User struct {
ID string ID string
Name string
Email string Email string
Password string Password string
} }
@ -43,6 +44,21 @@ func GetUserByEmail(dbPool *pgxpool.Pool, email string) (*User, error) {
return &user, nil return &user, nil
} }
// GetUserByID fetches a user by ID from the database.
func GetUserByID(dbPool *pgxpool.Pool, id string) (*User, error) {
if dbPool == nil {
return nil, errors.New("database connection pool is not initialized")
}
var user User
// Ensure the ID is being scanned as a string.
err := dbPool.QueryRow(context.Background(), "SELECT id::text, email, password FROM users WHERE id = $1", id).Scan(&user.ID, &user.Email, &user.Password)
if err != nil {
return nil, err
}
return &user, nil
}
// SaveUser saves a new user to the database. // SaveUser saves a new user to the database.
func SaveUser(dbPool *pgxpool.Pool, user *User) error { func SaveUser(dbPool *pgxpool.Pool, user *User) error {
if dbPool == nil { if dbPool == nil {

View file

@ -26,6 +26,7 @@ func InitializeSchema(dbPool *pgxpool.Pool) error {
const schemaSQL = ` const schemaSQL = `
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL, email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL password VARCHAR(255) NOT NULL
);` );`

View file

@ -21,6 +21,7 @@ import (
type SessionData struct { type SessionData struct {
SessionID string `json:"sessionID"` SessionID string `json:"sessionID"`
UserID string `json:"userId"` UserID string `json:"userId"`
Name string `json:"name"`
Email string `json:"email"` Email string `json:"email"`
Roles []string `json:"roles"` Roles []string `json:"roles"`
} }
@ -154,12 +155,21 @@ func ClearSessionCookie(w http.ResponseWriter, name string) {
// Checks if the user is signed in by checking the session cookie // Checks if the user is signed in by checking the session cookie
func IsSignedIn(c echo.Context) bool { func IsSignedIn(c echo.Context) bool {
_, err := GetSessionCookie(c.Request(), "session") sessionData, err := GetSessionCookie(c.Request(), "session")
if err != nil { if err != nil {
// Log the error for debugging purposes
log.Printf("Error retrieving session cookie: %v", err) log.Printf("Error retrieving session cookie: %v", err)
return false
} }
return err == nil
// Validate the session data by checking if the user exists in the database
user, err := GetUserByID(GetDBPool(), sessionData.UserID)
if err != nil || user == nil {
log.Printf("Session refers to a non-existent user: %v", err)
ClearSessionCookie(c.Response().Writer, "session")
return false
}
return true
} }
// GenerateRandomBytes returns securely generated random bytes. // GenerateRandomBytes returns securely generated random bytes.

View file

@ -8,7 +8,7 @@ import (
type DashboardProps struct { type DashboardProps struct {
IsLoggedIn bool IsLoggedIn bool
Email string Name string
} }
func Dashboard(c echo.Context) error { func Dashboard(c echo.Context) error {
@ -19,7 +19,7 @@ func Dashboard(c echo.Context) error {
props := DashboardProps{ props := DashboardProps{
IsLoggedIn: lib.IsSignedIn(c), IsLoggedIn: lib.IsSignedIn(c),
Email: currentSession.Email, Name: currentSession.Name,
} }
// Specify the partials used by this page // Specify the partials used by this page

View file

@ -13,7 +13,7 @@ Pollo // Dashboard
{{define "main"}} {{define "main"}}
<div class="flex flex-col items-center justify-center gap-8"> <div class="flex flex-col items-center justify-center gap-8">
<h1 class="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-4xl font-bold"> <h1 class="flex flex-row flex-wrap text-center justify-center items-center gap-1 text-4xl font-bold">
Hi, {{.Email}}! Hi, {{.Name}}!
</h1> </h1>
<label htmlFor="new-room-modal" class="btn btn-primary"> <label htmlFor="new-room-modal" class="btn btn-primary">

View file

@ -11,19 +11,21 @@ Pollo // Register
{{end}} {{end}}
{{define "main"}} {{define "main"}}
<div id="auth-form"> <div id="auth-form" hx-ext="response-targets">
<h2 class="text-4xl">Register</h2> <h2 class="text-4xl">Register</h2>
<br> <br>
<form class="flex flex-col gap-2" hx-post="/api/register" hx-swap="none"> <form class="flex flex-col gap-2" hx-post="/api/register" hx-target-4*="#error-message">
<input class="input input-bordered input-primary w-full max-w-xs" type="text" name="name" placeholder="Name" required>
<input class="input input-bordered input-primary w-full max-w-xs" type="email" name="email" placeholder="Email" required> <input class="input input-bordered input-primary w-full max-w-xs" type="email" name="email" placeholder="Email" required>
<input class="input input-bordered input-primary w-full max-w-xs" type="password" name="password" placeholder="Password" required> <input class="input input-bordered input-primary w-full max-w-xs" type="password" name="password" placeholder="Password" required>
<button class="btn btn-primary" type="submit">Register</button> <button class="btn btn-primary" type="submit">Sign In</button>
</form> </form>
<p>Already have an account? <a href="/signin">Sign In</a></p> <div id="error-message"style="color: red;"></div>
<p>Already have an account? <a href="/signin">Register</a></p>
</div> </div>
{{end}} {{end}}
{{define "foot"}} {{define "foot"}}
<script src="/public/js/htmx.base.js"></script> <script src="/public/js/htmx.base.js"></script>
<script src="/public/js/htmx.sse.js"></script> <script src="/public/js/htmx.targets.js"></script>
{{end}} {{end}}

View file

@ -26,6 +26,5 @@ Pollo // Sign In
{{define "foot"}} {{define "foot"}}
<script src="/public/js/htmx.base.js"></script> <script src="/public/js/htmx.base.js"></script>
<script src="/public/js/htmx.sse.js"></script>
<script src="/public/js/htmx.targets.js"></script> <script src="/public/js/htmx.targets.js"></script>
{{end}} {{end}}