feat: use postgres to fetch and store user info

This commit is contained in:
nihonium 2025-11-27 09:42:05 +03:00
parent 3528ea7d34
commit 40e0b14f2a
Signed by: nihonium
GPG key ID: 0251623741027CFC
9 changed files with 175 additions and 42 deletions

View file

@ -3,22 +3,21 @@ package handlers
import (
"context"
"fmt"
"log"
"net/http"
auth "nyanimedb/auth"
sqlc "nyanimedb/sql"
"strconv"
"time"
"github.com/alexedwards/argon2id"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
log "github.com/sirupsen/logrus"
)
var accessSecret = []byte("my_access_secret_key")
var refreshSecret = []byte("my_refresh_secret_key")
var UserDb = make(map[string]string) // TEMP: stores passwords
type Server struct {
db *sqlc.Queries
}
@ -32,6 +31,22 @@ func parseInt64(s string) (int32, error) {
return int32(i), err
}
func HashPassword(password string) (string, error) {
params := &argon2id.Params{
Memory: 64 * 1024,
Iterations: 3,
Parallelism: 2,
SaltLength: 16,
KeyLength: 32,
}
return argon2id.CreateHash(password, params)
}
func CheckPassword(password, hash string) (bool, error) {
return argon2id.ComparePasswordAndHash(password, hash)
}
func generateTokens(userID string) (accessToken string, refreshToken string, err error) {
accessClaims := jwt.MapClaims{
"user_id": userID,
@ -57,19 +72,27 @@ func generateTokens(userID string) (accessToken string, refreshToken string, err
}
func (s Server) PostAuthSignUp(ctx context.Context, req auth.PostAuthSignUpRequestObject) (auth.PostAuthSignUpResponseObject, error) {
err := ""
success := true
UserDb[req.Body.Nickname] = req.Body.Pass
passhash, err := HashPassword(req.Body.Pass)
if err != nil {
log.Errorf("failed to hash password: %v", err)
// TODO: return 500
}
user_id, err := s.db.CreateNewUser(context.Background(), sqlc.CreateNewUserParams{
Passhash: passhash,
Nickname: req.Body.Nickname,
})
if err != nil {
log.Errorf("failed to create user %s: %v", req.Body.Nickname, err)
// TODO: check err and retyrn 400/500
}
return auth.PostAuthSignUp200JSONResponse{
Error: &err,
Success: &success,
UserId: &req.Body.Nickname,
UserId: user_id,
}, nil
}
func (s Server) PostAuthSignIn(ctx context.Context, req auth.PostAuthSignInRequestObject) (auth.PostAuthSignInResponseObject, error) {
// ctx.SetCookie("122")
ginCtx, ok := ctx.Value(gin.ContextKey).(*gin.Context)
if !ok {
log.Print("failed to get gin context")
@ -77,27 +100,38 @@ func (s Server) PostAuthSignIn(ctx context.Context, req auth.PostAuthSignInReque
return auth.PostAuthSignIn200JSONResponse{}, fmt.Errorf("failed to get gin.Context from context.Context")
}
err := ""
user, err := s.db.GetUserByNickname(context.Background(), req.Body.Nickname)
if err != nil {
log.Errorf("failed to get user by nickname %s: %v", req.Body.Nickname, err)
// TODO: return 400/500
}
pass, ok := UserDb[req.Body.Nickname]
if !ok || pass != req.Body.Pass {
e := "invalid credentials"
ok, err = CheckPassword(req.Body.Pass, user.Passhash)
if err != nil {
log.Errorf("failed to check password for user %s: %v", req.Body.Nickname, err)
// TODO: return 500
}
if !ok {
err_msg := "invalid credentials"
return auth.PostAuthSignIn401JSONResponse{
Error: &e,
Error: &err_msg,
}, nil
}
accessToken, refreshToken, _ := generateTokens(req.Body.Nickname)
accessToken, refreshToken, err := generateTokens(req.Body.Nickname)
if err != nil {
log.Errorf("failed to generate tokens for user %s: %v", req.Body.Nickname, err)
// TODO: return 500
}
// TODO: check cookie settings carefully
ginCtx.SetSameSite(http.SameSiteStrictMode)
ginCtx.SetCookie("access_token", accessToken, 604800, "/auth", "", true, true)
ginCtx.SetCookie("refresh_token", refreshToken, 604800, "/api", "", true, true)
ginCtx.SetCookie("access_token", accessToken, 604800, "/auth", "", false, true)
ginCtx.SetCookie("refresh_token", refreshToken, 604800, "/api", "", false, true)
// Return access token; refresh token can be returned in response or HttpOnly cookie
result := auth.PostAuthSignIn200JSONResponse{
Error: &err,
UserId: &req.Body.Nickname,
UserName: &req.Body.Nickname,
UserId: user.ID,
UserName: user.Nickname,
}
return result, nil
}