200 lines
5.3 KiB
Go
200 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func Login(w http.ResponseWriter, r *http.Request) {
|
|
var creds Credentials
|
|
err := r.ParseMultipartForm(0)
|
|
if err != nil {
|
|
log.Printf("Error parsing form: %v", err)
|
|
http.Error(w, "Bad Request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
log.Println(r.FormValue("username"))
|
|
creds.Username = strings.ToLower(r.FormValue("username"))
|
|
creds.Password = r.FormValue("password")
|
|
|
|
// Retrieve the hashed password from the database
|
|
hashedPassword, userExists := getUserFromDatabase(creds.Username)
|
|
if !userExists {
|
|
errorMessage := creds.Username + " does not exist"
|
|
log.Println(errorMessage)
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": "Incorrect username or password",
|
|
})
|
|
return
|
|
}
|
|
|
|
// Compare the stored hashed password with the provided password
|
|
err = bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(creds.Password))
|
|
if err != nil {
|
|
errorMessage := "Incorrect username or password"
|
|
log.Println(errorMessage)
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": errorMessage,
|
|
})
|
|
return
|
|
}
|
|
|
|
// Create a new session token
|
|
sessionToken := uuid.NewString()
|
|
expiresAt := time.Now().Add(sessionLength)
|
|
|
|
// Store the token in the session map
|
|
sessions[sessionToken] = session{
|
|
username: creds.Username,
|
|
expiry: expiresAt,
|
|
}
|
|
|
|
// Set the session token as a cookie
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "session_token",
|
|
Value: sessionToken,
|
|
Expires: expiresAt,
|
|
})
|
|
|
|
log.Printf("User logged in: %s", creds.Username)
|
|
|
|
// Send JSON response indicating successful login
|
|
w.WriteHeader(http.StatusOK)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"message": "Login successful",
|
|
})
|
|
}
|
|
|
|
func getUserFromDatabase(username string) (string, bool) {
|
|
var hashedPassword string
|
|
err := db.QueryRow("SELECT password FROM users WHERE username = $1", username).Scan(&hashedPassword)
|
|
if err == sql.ErrNoRows {
|
|
// User not found
|
|
return "", false
|
|
} else if err != nil {
|
|
log.Printf("Error retrieving user from the database: %v", err)
|
|
return "", false
|
|
}
|
|
|
|
return hashedPassword, true
|
|
}
|
|
|
|
func getUserUUID(username string) (string, error) {
|
|
var uuid string
|
|
err := db.QueryRow("SELECT uuid FROM users WHERE username = $1", username).Scan(&uuid)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
// User not found
|
|
return "", fmt.Errorf("user not found: %s", username)
|
|
}
|
|
return "", err
|
|
}
|
|
return uuid, nil
|
|
}
|
|
|
|
func Logout(w http.ResponseWriter, r *http.Request) {
|
|
// Get the session token from the request cookies
|
|
sessionCookie, err := r.Cookie("session_token")
|
|
if err != nil {
|
|
log.Printf("Error getting session cookie: %v", err)
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
sessionToken := sessionCookie.Value
|
|
|
|
// Remove the user's session from the session map
|
|
delete(sessions, sessionToken)
|
|
|
|
log.Printf("User logged out")
|
|
|
|
// Set the user's `session_token` cookie to an empty value and an immediate expiry time
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "session_token",
|
|
Value: "",
|
|
Expires: time.Now(),
|
|
})
|
|
|
|
// Redirect to the index page
|
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
|
}
|
|
|
|
func Signup(w http.ResponseWriter, r *http.Request) {
|
|
// Check if the request method is POST
|
|
if r.Method == http.MethodPost {
|
|
var creds Credentials
|
|
err := r.ParseForm()
|
|
if err != nil {
|
|
log.Printf("Error parsing form: %v", err)
|
|
http.Error(w, "Bad Request", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
creds.Username = strings.ToLower(r.FormValue("username"))
|
|
creds.Password = r.FormValue("password")
|
|
name := r.FormValue("name")
|
|
email := r.FormValue("email")
|
|
// Check if the username is already taken
|
|
if _, userExists := getUserFromDatabase(creds.Username); userExists {
|
|
log.Printf("Username already exists: %s", creds.Username)
|
|
http.Error(w, "Username Already Taken", http.StatusConflict)
|
|
return
|
|
}
|
|
|
|
// Hash the user's password
|
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(creds.Password), hashCost)
|
|
if err != nil {
|
|
log.Printf("Error hashing password: %v", err)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Generate a UUID for the user
|
|
userUUID := uuid.New()
|
|
|
|
// Store the user in the database with the generated UUID
|
|
if err := insertUserIntoDatabase(creds.Username, string(hashedPassword), string("normal"), userUUID.String(), name, email); err != nil {
|
|
log.Printf("Error inserting user into database: %v", err)
|
|
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Create a new session token
|
|
sessionToken := uuid.NewString()
|
|
expiresAt := time.Now().Add(sessionLength)
|
|
|
|
// Store the token in the session map
|
|
sessions[sessionToken] = session{
|
|
username: creds.Username,
|
|
expiry: expiresAt,
|
|
sessionUUID: userUUID.String(),
|
|
}
|
|
|
|
// Set the session token as a cookie
|
|
http.SetCookie(w, &http.Cookie{
|
|
Name: "session_token",
|
|
Value: sessionToken,
|
|
Expires: expiresAt,
|
|
})
|
|
|
|
log.Printf("User signed up and added to database: %s", creds.Username)
|
|
|
|
createUserFolder(creds.Username)
|
|
|
|
// Redirect to the new user page
|
|
http.Redirect(w, r, "/welcome", http.StatusSeeOther)
|
|
return
|
|
}
|
|
|
|
}
|