package handlers import ( "context" "fmt" "log" "net/http" auth "nyanimedb/auth" sqlc "nyanimedb/sql" "strconv" "time" "github.com/gin-gonic/gin" "github.com/golang-jwt/jwt/v5" ) 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 } func NewServer(db *sqlc.Queries) Server { return Server{db: db} } func parseInt64(s string) (int32, error) { i, err := strconv.ParseInt(s, 10, 64) return int32(i), err } func generateTokens(userID string) (accessToken string, refreshToken string, err error) { accessClaims := jwt.MapClaims{ "user_id": userID, "exp": time.Now().Add(15 * time.Minute).Unix(), } at := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims) accessToken, err = at.SignedString(accessSecret) if err != nil { return "", "", err } refreshClaims := jwt.MapClaims{ "user_id": userID, "exp": time.Now().Add(7 * 24 * time.Hour).Unix(), } rt := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims) refreshToken, err = rt.SignedString(refreshSecret) if err != nil { return "", "", err } return accessToken, refreshToken, nil } func (s Server) PostAuthSignUp(ctx context.Context, req auth.PostAuthSignUpRequestObject) (auth.PostAuthSignUpResponseObject, error) { err := "" success := true UserDb[req.Body.Nickname] = req.Body.Pass return auth.PostAuthSignUp200JSONResponse{ Error: &err, Success: &success, UserId: &req.Body.Nickname, }, 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") // TODO: change to 500 return auth.PostAuthSignIn200JSONResponse{}, fmt.Errorf("failed to get gin.Context from context.Context") } err := "" success := true pass, ok := UserDb[req.Body.Nickname] if !ok || pass != req.Body.Pass { e := "invalid credentials" return auth.PostAuthSignIn401JSONResponse{ Error: &e, }, nil } accessToken, refreshToken, _ := generateTokens(req.Body.Nickname) ginCtx.SetSameSite(http.SameSiteStrictMode) ginCtx.SetCookie("access_token", accessToken, 604800, "/auth", "", true, true) ginCtx.SetCookie("refresh_token", refreshToken, 604800, "/api", "", true, true) // Return access token; refresh token can be returned in response or HttpOnly cookie result := auth.PostAuthSignIn200JSONResponse{ Error: &err, Success: &success, UserId: &req.Body.Nickname, } return result, nil } // func (s Server) PostAuthVerifyToken(ctx context.Context, req auth.PostAuthVerifyTokenRequestObject) (auth.PostAuthVerifyTokenResponseObject, error) { // valid := false // var userID *string // var errStr *string // token, err := jwt.Parse(req.Body.Token, func(t *jwt.Token) (interface{}, error) { // if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { // return nil, fmt.Errorf("unexpected signing method") // } // return accessSecret, nil // }) // if err != nil { // e := err.Error() // errStr = &e // return auth.PostAuthVerifyToken200JSONResponse{ // Valid: &valid, // UserId: userID, // Error: errStr, // }, nil // } // if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { // if uid, ok := claims["user_id"].(string); ok { // valid = true // userID = &uid // } else { // e := "user_id not found in token" // errStr = &e // } // } else { // e := "invalid token claims" // errStr = &e // } // return auth.PostAuthVerifyToken200JSONResponse{ // Valid: &valid, // UserId: userID, // Error: errStr, // }, nil // } // func (s Server) PostAuthRefreshToken(ctx context.Context, req auth.PostAuthRefreshTokenRequestObject) (auth.PostAuthRefreshTokenResponseObject, error) { // valid := false // var userID *string // var errStr *string // token, err := jwt.Parse(req.Body.Token, func(t *jwt.Token) (interface{}, error) { // if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok { // return nil, fmt.Errorf("unexpected signing method") // } // return refreshSecret, nil // }) // if err != nil { // e := err.Error() // errStr = &e // return auth.PostAuthVerifyToken200JSONResponse{ // Valid: &valid, // UserId: userID, // Error: errStr, // }, nil // } // if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { // if uid, ok := claims["user_id"].(string); ok { // // Refresh token is valid, generate new tokens // newAccessToken, newRefreshToken, _ := generateTokens(uid) // valid = true // userID = &uid // return auth.PostAuthVerifyToken200JSONResponse{ // Valid: &valid, // UserId: userID, // Error: nil, // Token: &newAccessToken, // return new access token // // optionally return newRefreshToken as well // }, nil // } else { // e := "user_id not found in refresh token" // errStr = &e // } // } else { // e := "invalid refresh token claims" // errStr = &e // } // return auth.PostAuthVerifyToken200JSONResponse{ // Valid: &valid, // UserId: userID, // Error: errStr, // }, nil // }