3.28.3: Исправлена проблема с refresh token
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 54s
Some checks failed
Build and Push Docker Image / build-and-push (push) Failing after 54s
This commit is contained in:
@@ -1018,10 +1018,7 @@ func (a *App) refreshTokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Delete old refresh token
|
||||
a.DB.Exec("DELETE FROM refresh_tokens WHERE id = $1", foundTokenID)
|
||||
|
||||
// Generate new tokens
|
||||
// Generate new tokens FIRST before deleting old one to prevent race condition
|
||||
accessToken, err := a.generateAccessToken(user.ID)
|
||||
if err != nil {
|
||||
log.Printf("Error generating access token: %v", err)
|
||||
@@ -1036,12 +1033,21 @@ func (a *App) refreshTokenHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// Store new refresh token
|
||||
// Store new refresh token FIRST
|
||||
refreshTokenHash, _ := hashPassword(refreshToken)
|
||||
a.DB.Exec(`
|
||||
_, err = a.DB.Exec(`
|
||||
INSERT INTO refresh_tokens (user_id, token_hash, expires_at)
|
||||
VALUES ($1, $2, $3)
|
||||
`, user.ID, refreshTokenHash, nil)
|
||||
if err != nil {
|
||||
log.Printf("Error storing new refresh token: %v", err)
|
||||
sendErrorWithCORS(w, "Error generating token", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Delete old refresh token AFTER new one is successfully stored
|
||||
// This prevents race condition where multiple refresh requests might use the same token
|
||||
a.DB.Exec("DELETE FROM refresh_tokens WHERE id = $1", foundTokenID)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(TokenResponse{
|
||||
@@ -2818,6 +2824,29 @@ func (a *App) initAuthDB() error {
|
||||
a.DB.Exec("CREATE INDEX IF NOT EXISTS idx_refresh_tokens_user_id ON refresh_tokens(user_id)")
|
||||
a.DB.Exec("CREATE INDEX IF NOT EXISTS idx_refresh_tokens_token_hash ON refresh_tokens(token_hash)")
|
||||
|
||||
// Apply migration 014: Make refresh tokens permanent (expires_at nullable)
|
||||
// This allows refresh tokens to never expire
|
||||
var isNullable string
|
||||
err = a.DB.QueryRow(`
|
||||
SELECT is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema = 'public'
|
||||
AND table_name = 'refresh_tokens'
|
||||
AND column_name = 'expires_at'
|
||||
`).Scan(&isNullable)
|
||||
if err == nil && isNullable == "NO" {
|
||||
// Column is NOT NULL, need to make it nullable
|
||||
if _, err := a.DB.Exec("ALTER TABLE refresh_tokens ALTER COLUMN expires_at DROP NOT NULL"); err != nil {
|
||||
log.Printf("Warning: Failed to apply migration 014 (make expires_at nullable): %v", err)
|
||||
} else {
|
||||
log.Printf("Migration 014 applied: refresh_tokens.expires_at is now nullable")
|
||||
}
|
||||
} else if err == nil && isNullable == "YES" {
|
||||
// Migration already applied
|
||||
log.Printf("Migration 014 already applied (expires_at is nullable), skipping")
|
||||
}
|
||||
// If err != nil, column might not exist yet (shouldn't happen, but ignore)
|
||||
|
||||
// Add user_id column to all tables if not exists
|
||||
tables := []string{"projects", "entries", "nodes", "dictionaries", "words", "progress", "configs", "telegram_integrations", "weekly_goals", "tasks"}
|
||||
for _, table := range tables {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "play-life-web",
|
||||
"version": "3.28.2",
|
||||
"version": "3.28.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
Reference in New Issue
Block a user