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.ParseMultipartForm(0) 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 } }