package endpoints import ( "encoding/json" "net/http" "time" "github.com/golang-jwt/jwt/v4" "github.com/imosed/signet/auth" . "github.com/imosed/signet/data" "github.com/rs/zerolog/log" "github.com/spf13/viper" ) type LoginResponse struct { Token *string `json:"token"` LastLogin *time.Time `json:"lastLogin"` } func Login(w http.ResponseWriter, r *http.Request) { var req AuthenticationRequest err := json.NewDecoder(r.Body).Decode(&req) if err != nil { log.Error().Err(err).Msg("Failed to decode body in login attempt") return } var userData User var loginTime = time.Now() var resp LoginResponse Db.Table("users").Select("id, password, privileges, last_login"). Where("username = ?", req.Username).First(&userData) var passwordMatches bool passwordMatches, err = ComparePasswordAndHash(req.Password, userData.Password) if err != nil { log.Error().Err(err).Msg("Could not compare password to hash in login attempt") return } if !passwordMatches { err = json.NewEncoder(w).Encode(resp) if err != nil { log.Error().Err(err).Msg("Failed to deliver failed login attempt response") } return } token := jwt.NewWithClaims(jwt.SigningMethodHS256, &auth.Claims{ ID: userData.ID, Username: req.Username, Privileges: userData.Privileges, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(loginTime.Add(10 * time.Hour)), }, }) secret := viper.GetString("app.secretKey") tokenString, err := token.SignedString([]byte(secret)) if err != nil { log.Error().Err(err).Msg("Could not generate JWT token") return } resp.Token = &tokenString resp.LastLogin = userData.LastLogin if userData.LastLogin != nil { // need to set this after the user changes their password Db.Table("users").Where("id = ?", userData.ID).Update("last_login", loginTime) } err = json.NewEncoder(w).Encode(resp) if err != nil { log.Error().Err(err).Msg("Could not deliver response in Login call") } }