Skip to content

Commit

Permalink
password reset & minor bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mytja committed Nov 17, 2023
1 parent bbcba87 commit 0e78069
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 2 deletions.
77 changes: 77 additions & 0 deletions backend/internal/httphandlers/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ package httphandlers

import (
"encoding/json"
"fmt"
"github.com/mytja/Tarok/backend/internal/sql"
mail "github.com/xhit/go-simple-mail/v2"
"net/http"
"time"
)

func (s *httpImpl) GetUserData(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -102,6 +105,80 @@ func (s *httpImpl) ChangePassword(w http.ResponseWriter, r *http.Request) {
return
}

go func() {
smtp := mail.NewSMTPClient()
smtp.Host = s.config.EmailServer
smtp.Port = s.config.EmailPort
smtp.Username = s.config.EmailAccount
smtp.Password = s.config.EmailPassword
smtp.Encryption = mail.EncryptionTLS

smtpClient, err := smtp.Connect()
if err != nil {
s.sugared.Error(err)
}

// Create email
msg := mail.NewMSG()
msg.SetFrom("Palčka <[email protected]>")
msg.AddTo(user.Email)
msg.SetSubject("Sprememba gesla na palcka.si")

emailConfirmationText := fmt.Sprintf(`
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Tarok Palčka</title>
</head>
<body>
<div style="margin-left:auto;margin-right:auto;">
<h1>Sprememba gesla na palcka.si</h1>
Uradna instanca <b>palcka.si</b>
</div>
<p/>
Spoštovani,
<p/>
nekdo je ravnokar (%s) uspešno spremenil vaše geslo.
Če tega dejanja niste izvršili vi, si čim prej spremenite geslo vašega računa na Palčki.
Nujno kontaktirajte razvijalca in vzdrževalca sistema na eni izmed spodaj naštetih metod (na Discordu dobite najhitrejši odgovor).
<p/>
Če ste to dejanje izvršili vi, lahko mirno ignorirate to elektronsko pošto.
<p/>
Hvala za zaupanje
<p/>
Ekipa palcka.si
<p/>
<hr>
<p/>
Kontaktne možnosti:
<li><a href="https://discord.gg/cTZMCktwcK">Discord strežnik Palčka</a>,</li>
<li><a href="mailto:[email protected]">Kontaktna elektronska pošta</a>,</li>
<li><a href="https://discord.com/users/761599472454205531">Direktni kontakt razvijalca na Discordu (@mytja)</a>.</li>
</body>
</html>
`, time.Now().Format("02. 01. 2006 ob 15.04"))

msg.SetBody(mail.TextHTML, emailConfirmationText)

err = msg.Send(smtpClient)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
}()

w.WriteHeader(http.StatusOK)
}

Expand Down
2 changes: 2 additions & 0 deletions backend/internal/httphandlers/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ type HTTPHandler interface {
PromoteDemoteUser(w http.ResponseWriter, r *http.Request)
GetUserData(w http.ResponseWriter, r *http.Request)
Logout(w http.ResponseWriter, r *http.Request)
RequestPasswordReset(w http.ResponseWriter, r *http.Request)
PasswordResetConfirm(w http.ResponseWriter, r *http.Request)
}

func NewHTTPHandler(db sql.SQL, config *consts.ServerConfig, sugared *zap.SugaredLogger) HTTPHandler {
Expand Down
269 changes: 269 additions & 0 deletions backend/internal/httphandlers/password_reset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
package httphandlers

import (
"fmt"
"github.com/mytja/Tarok/backend/internal/sql"
mail "github.com/xhit/go-simple-mail/v2"
"math/rand"
"net/http"
"strings"
"time"
)

func (s *httpImpl) RequestPasswordReset(w http.ResponseWriter, r *http.Request) {
email := r.FormValue("email")
if email == "" {
s.sugared.Errorw("empty fields", "email", email)
w.WriteHeader(http.StatusBadRequest)
return
}

user, err := s.db.GetUserByEmail(email)
if err != nil {
s.sugared.Errorw("error while fetching from database", "err", err)
w.WriteHeader(http.StatusInternalServerError)
return
}

if user.Disabled || !user.EmailConfirmed {
w.WriteHeader(http.StatusInternalServerError)
return
}

chars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789")
length := 40
var b strings.Builder
for i := 0; i < length; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
resetToken := b.String()

n := time.Now()
user.PasswordResetInitiatedOn = n.Format(time.RFC3339)
user.PasswordResetToken = resetToken

s.sugared.Debugw("requesting password reset", "email", email, "userId", user.ID)

err = s.db.UpdateUser(user)
if err != nil {
s.sugared.Errorw("updating user in the database has failed", "err", err)
w.WriteHeader(http.StatusInternalServerError)
return
}

go func() {
smtp := mail.NewSMTPClient()
smtp.Host = s.config.EmailServer
smtp.Port = s.config.EmailPort
smtp.Username = s.config.EmailAccount
smtp.Password = s.config.EmailPassword
smtp.Encryption = mail.EncryptionTLS

smtpClient, err := smtp.Connect()
if err != nil {
s.sugared.Error(err)
}

// Create email
msg := mail.NewMSG()
msg.SetFrom("Palčka <[email protected]>")
msg.AddTo(email)
msg.SetSubject("Zahtevek za ponastavitev gesla na tarok strežniku palcka.si")

emailConfirmationText := fmt.Sprintf(`
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Tarok Palčka</title>
</head>
<body>
<div style="margin-left:auto;margin-right:auto;">
<h1>Zahtevek za ponastavitev gesla na tarok strežniku palcka.si</h1>
Uradna instanca <b>palcka.si</b>
</div>
<p/>
Spoštovani,
<p/>
nekdo je %s zahteval ponastavitev vašega gesla.
Če tega dejanja niste izvršili vi, je priporočljivo, da si čim prej spremenite geslo,
po potrebi pa lahko kontaktirate tudi razvijalca in glavnega administratorja sistema, ki lahko zaklene
vaš račun in tako poskrbi, da se prepreči dostop do računa.
<p/>
Povezava za ponastavitev poteče čez 72 ur. <b>Ne delite te povezave z nikomer drugim, niti z razvijalcem.</b>
<p/>
Vaš račun lahko potrdite z obiskom strani <a href="https://palcka.si/password/reset?email=%s&resetCode=%s">https://palcka.si/password/reset?email=%s&resetCode=%s</a>. Pri tem se prepričajte, da vas pelje na uradno stran (na domeni palcka.si).
<p/>
Hvala za zaupanje
<p/>
Ekipa palcka.si
<p/>
<hr>
<p/>
Kontaktne možnosti:
<li><a href="https://discord.gg/cTZMCktwcK">Discord strežnik Palčka</a>,</li>
<li><a href="mailto:[email protected]">Kontaktna elektronska pošta</a>,</li>
<li><a href="https://discord.com/users/761599472454205531">Direktni kontakt razvijalca na Discordu (@mytja)</a>.</li>
</body>
</html>
`, n.Format("02. 01. 2006 ob 15.04"), email, resetToken, email, resetToken)

msg.SetBody(mail.TextHTML, emailConfirmationText)

err = msg.Send(smtpClient)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
}()

w.WriteHeader(http.StatusCreated)
}

func (s *httpImpl) PasswordResetConfirm(w http.ResponseWriter, r *http.Request) {
email := r.FormValue("email")
resetCode := r.FormValue("resetCode")
newPassword := r.FormValue("newPassword")
if email == "" || resetCode == "" || newPassword == "" {
w.WriteHeader(http.StatusBadRequest)
return
}

user, err := s.db.GetUserByEmail(email)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
s.sugared.Debugw("could not fetch user by email", "email", email)
return
}

passwordResetDate, err := time.Parse(time.RFC3339, user.PasswordResetInitiatedOn)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
s.sugared.Debugw("could not parse time", "email", email, "reset", user.PasswordResetInitiatedOn)
return
}

if time.Now().Sub(passwordResetDate).Hours() >= 72 {
w.WriteHeader(http.StatusInternalServerError)
return
}

if resetCode != user.PasswordResetToken {
w.WriteHeader(http.StatusInternalServerError)
return
}

if user.PasswordResetToken == "" {
w.WriteHeader(http.StatusInternalServerError)
return
}

password, err := sql.HashPassword(newPassword)
if err != nil {
s.sugared.Errorw("error while hashing new password", "user", user.ID, "err", err)
w.WriteHeader(http.StatusInternalServerError)
return
}

user.Password = password
user.LoginToken = ""
user.PasswordResetToken = ""

err = s.db.UpdateUser(user)
if err != nil {
s.sugared.Errorw("error while updating user", "user", user.ID, "err", err)
w.WriteHeader(http.StatusInternalServerError)
return
}

go func() {
smtp := mail.NewSMTPClient()
smtp.Host = s.config.EmailServer
smtp.Port = s.config.EmailPort
smtp.Username = s.config.EmailAccount
smtp.Password = s.config.EmailPassword
smtp.Encryption = mail.EncryptionTLS

smtpClient, err := smtp.Connect()
if err != nil {
s.sugared.Error(err)
}

// Create email
msg := mail.NewMSG()
msg.SetFrom("Palčka <[email protected]>")
msg.AddTo(email)
msg.SetSubject("Sprememba gesla na palcka.si")

emailConfirmationText := fmt.Sprintf(`
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Tarok Palčka</title>
</head>
<body>
<div style="margin-left:auto;margin-right:auto;">
<h1>Sprememba gesla na palcka.si</h1>
Uradna instanca <b>palcka.si</b>
</div>
<p/>
Spoštovani,
<p/>
nekdo je ravnokar (%s) uspešno izvršil ponastavitev vašega gesla.
Če tega dejanja niste izvršili vi, si čim prej spremenite geslo vašega poštnega predala, kot tudi računa na Palčki.
Nujno kontaktirajte razvijalca in vzdrževalca sistema na eni izmed spodaj naštetih metod (na Discordu dobite najhitrejši odgovor).
<p/>
Če ste to dejanje izvršili vi, lahko mirno ignorirate to elektronsko pošto.
<p/>
Hvala za zaupanje
<p/>
Ekipa palcka.si
<p/>
<hr>
<p/>
Kontaktne možnosti:
<li><a href="https://discord.gg/cTZMCktwcK">Discord strežnik Palčka</a>,</li>
<li><a href="mailto:[email protected]">Kontaktna elektronska pošta</a>,</li>
<li><a href="https://discord.com/users/761599472454205531">Direktni kontakt razvijalca na Discordu (@mytja)</a>.</li>
</body>
</html>
`, time.Now().Format("02. 01. 2006 ob 15.04"))

msg.SetBody(mail.TextHTML, emailConfirmationText)

err = msg.Send(smtpClient)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
}()

w.WriteHeader(http.StatusOK)
}
5 changes: 3 additions & 2 deletions backend/internal/ws/gameend.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ func (s *serverImpl) EndGame(gameId string) {
return
}

events.Publish("lobby.broadcast", &lobby_messages.LobbyMessage{Data: &lobby_messages.LobbyMessage_GameDisbanded{GameDisbanded: &lobby_messages.GameDisbanded{GameId: gameId}}})

results := make([]*messages.ResultsUser, 0)
for u, user := range game.Players {
if !user.GetBotStatus() && game.Started {
Expand Down Expand Up @@ -73,8 +71,11 @@ func (s *serverImpl) EndGame(gameId string) {
s.Broadcast("", gameId, &messages.Message{Data: &messages.Message_GameEnd{GameEnd: &messages.GameEnd{Type: &messages.GameEnd_Results{Results: &messages.Results{
User: results,
}}}}})
time.Sleep(200 * time.Millisecond)
events.Publish("lobby.broadcast", &lobby_messages.LobbyMessage{Data: &lobby_messages.LobbyMessage_GameDisbanded{GameDisbanded: &lobby_messages.GameDisbanded{GameId: gameId}}})
time.Sleep(3 * time.Second) // nekaj spanca, preden izbrišemo vse skupaj.
delete(s.games, gameId)
events.Publish("lobby.broadcast", &lobby_messages.LobbyMessage{Data: &lobby_messages.LobbyMessage_GameDisbanded{GameDisbanded: &lobby_messages.GameDisbanded{GameId: gameId}}})
}

func (s *serverImpl) GameAddRounds(userId string, gameId string, rounds int) {
Expand Down
Loading

0 comments on commit 0e78069

Please sign in to comment.