You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
2.8 KiB
105 lines
2.8 KiB
package routes
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/jacobmveber-01839764/BudgetBuddy/db"
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
"go.mongodb.org/mongo-driver/mongo/readpref"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type UserSchema struct {
|
|
Name string `json:"name" bson:"name"`
|
|
Email string `json:"email" bson:"email"`
|
|
Password string `json:"password" bson:"password"`
|
|
Session string `json:"session" bson:"session"`
|
|
}
|
|
|
|
type LoginResponse struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
Session string `json:"session"`
|
|
}
|
|
|
|
func Login(w http.ResponseWriter, r *http.Request) {
|
|
// prepare DB
|
|
err := db.Client.Ping(context.Background(), readpref.Primary())
|
|
if err != nil {
|
|
db.Connect()
|
|
}
|
|
var userCollection = db.Client.Database("budgetbuddy").Collection("users")
|
|
|
|
// var v contains POST credentials
|
|
var v UserSchema
|
|
r.ParseForm()
|
|
v.Email = r.FormValue("email")
|
|
v.Password = r.FormValue("password")
|
|
if v.Email == "" || v.Password == "" {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// cmp struct will be compared with v to verify credentials
|
|
var cmp UserSchema
|
|
|
|
found := userCollection.FindOne(r.Context(), bson.D{primitive.E{Key: "email", Value: strings.ToLower(v.Email)}})
|
|
if found.Err() != nil {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
fmt.Fprintf(w, "{\"error\":\"account with that email does not exist\"}")
|
|
return
|
|
}
|
|
err = found.Decode(&cmp)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
err = bcrypt.CompareHashAndPassword([]byte(cmp.Password), []byte(v.Password))
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
fmt.Fprintf(w, "{\"error\":\"invalid password\"}")
|
|
return
|
|
}
|
|
|
|
// prepare ReturnedAccount struct to be sent back to the client
|
|
var account LoginResponse
|
|
err = found.Decode(&account)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// set new session cookie for user, either persistent (remember me) or temporary
|
|
sessionID := uuid.NewString()
|
|
var session = &http.Cookie{
|
|
Name: "session",
|
|
Value: sessionID,
|
|
Path: "/",
|
|
Secure: true,
|
|
SameSite: http.SameSiteLaxMode,
|
|
MaxAge: 0,
|
|
}
|
|
http.SetCookie(w, session)
|
|
|
|
// update the new user session in the DB
|
|
filter := bson.D{primitive.E{Key: "email", Value: strings.ToLower(account.Email)}}
|
|
opts := options.Update().SetUpsert(true)
|
|
update := bson.D{primitive.E{Key: "$set", Value: bson.D{primitive.E{Key: "session", Value: sessionID}}}}
|
|
userCollection.UpdateOne(context.TODO(), filter, update, opts)
|
|
|
|
acc, err := json.Marshal(account)
|
|
if err != nil {
|
|
fmt.Println("Error marshalling bson.D response")
|
|
}
|
|
fmt.Fprint(w, string(acc))
|
|
// fmt.Println("logged in user successfully")
|
|
}
|