diff --git a/cmd/main.go b/cmd/main.go index 6c0f6bd..7ea0a48 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -19,10 +19,14 @@ func initGin() { r.SetTrustedProxies([]string{"localhost"}) r.GET("/ping", internal.Ping) + r.GET("/get-all-articles", internal.GetAllArticles) r.POST("/add-article", internal.AddArticle) r.DELETE("/delete-article", internal.DeleteArticle) + r.POST("/login", internal.LoginUser) + r.POST("/logout", internal.LogoutUser) + r.Run(":" + os.Getenv("API_PORT")) } diff --git a/internal/auth.go b/internal/auth.go new file mode 100644 index 0000000..177664a --- /dev/null +++ b/internal/auth.go @@ -0,0 +1,79 @@ +package internal + +import ( + "crypto/sha256" + "errors" + "fmt" + + "github.com/gin-gonic/gin" +) + +type User struct { + Email string `json:"email" bson:"email"` + Password string `json:"password" bson:"password"` +} + +var USERS_LOCATION = Location{Database: "gohcms", Collection: "users"} + +func getUserHashedPassword(user User) string { + password := sha256.New() + password.Write([]byte(user.Password)) + return fmt.Sprintf("%x", password.Sum(nil)) +} + +func isUserLoggedIn(user User) bool { + for i := 0; i < len(SESSIONS); i++ { + hash1 := fmt.Sprint(SESSIONS[i].Token.Sum(nil)) + hash2 := fmt.Sprint(generateSessionToken(user).Sum(nil)) + if hash1 != hash2 { + continue + } + return !isSessionExpired(SESSIONS[i]) + } + return false +} + +func isUserReal(user User) bool { + docUsers, _ := getDocuments(USERS_LOCATION, user) + return len(docUsers) == 1 +} + +func parseUserFromContext(c *gin.Context) (User, error) { + var user User + if c.BindJSON(&user) != nil { + SendErrorMessageToClient(c, "Could not correctly parse user crendentials.") + return User{}, errors.New("could not correctly parse user crendentials") + } + user.Password = getUserHashedPassword(user) + return user, nil +} + +func LoginUser(c *gin.Context) { + user, err := parseUserFromContext(c) + if err != nil { + return + } + if isUserLoggedIn(user) { + SendErrorMessageToClient(c, "User is already logged in!") + return + } + if !isUserReal(user) { + SendErrorMessageToClient(c, "Unknown email or wrong password.") + return + } + addSession(user) + SendOkMessageToClient(c, "User successfully logged in.") +} + +func LogoutUser(c *gin.Context) { + user, err := parseUserFromContext(c) + if err != nil { + return + } + if !isUserLoggedIn(user) { + SendErrorMessageToClient(c, "User is not logged in!") + return + } + removeSession(user) + SendOkMessageToClient(c, "User successfully logged out.") +} diff --git a/internal/sessions.go b/internal/sessions.go new file mode 100644 index 0000000..b8adf40 --- /dev/null +++ b/internal/sessions.go @@ -0,0 +1,51 @@ +package internal + +import ( + "crypto" + "fmt" + "hash" + "time" +) + +type Session struct { + Token hash.Hash `json:"token"` + ExpirationTimestamp int64 `json:"expirationTimestamp"` +} + +var SESSIONS []Session + +const SESSION_DURATION int64 = 3600 + +func generateSessionToken(user User) hash.Hash { + token := crypto.SHA256.New() + stringToHash := fmt.Sprintf(user.Email + user.Password) + token.Write([]byte(stringToHash)) + return token +} + +func isSessionExpired(session Session) bool { + return session.ExpirationTimestamp < time.Now().Unix() +} + +func addSession(user User) { + SESSIONS = append(SESSIONS, Session{ + Token: generateSessionToken(user), + ExpirationTimestamp: time.Now().Unix() + SESSION_DURATION, + }) +} + +func removeSession(user User) { + index := 0 + sessLen := len(SESSIONS) + for i := 0; i < sessLen; i++ { + if SESSIONS[i].Token == generateSessionToken(user) { + index = i + break + } + } + fmt.Println(SESSIONS) + SESSIONS[index] = SESSIONS[sessLen-1] + SESSIONS[sessLen-1] = Session{} //TODO PAS SUR QUE ÇA FONCTIONNE + SESSIONS = SESSIONS[:sessLen-1] + fmt.Println(SESSIONS) +}