user_session.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package storage // import "miniflux.app/v2/internal/storage"
  4. import (
  5. "crypto/rand"
  6. "database/sql"
  7. "fmt"
  8. "time"
  9. "miniflux.app/v2/internal/model"
  10. )
  11. // UserSessions returns the list of sessions for the given user.
  12. func (s *Storage) UserSessions(userID int64) ([]model.UserSession, error) {
  13. query := `
  14. SELECT
  15. id,
  16. user_id,
  17. token,
  18. created_at,
  19. user_agent,
  20. ip
  21. FROM
  22. user_sessions
  23. WHERE
  24. user_id=$1 ORDER BY id DESC
  25. `
  26. rows, err := s.db.Query(query, userID)
  27. if err != nil {
  28. return nil, fmt.Errorf(`store: unable to fetch user sessions: %v`, err)
  29. }
  30. defer rows.Close()
  31. var sessions []model.UserSession
  32. for rows.Next() {
  33. var session model.UserSession
  34. err := rows.Scan(
  35. &session.ID,
  36. &session.UserID,
  37. &session.Token,
  38. &session.CreatedAt,
  39. &session.UserAgent,
  40. &session.IP,
  41. )
  42. if err != nil {
  43. return nil, fmt.Errorf(`store: unable to fetch user session row: %v`, err)
  44. }
  45. sessions = append(sessions, session)
  46. }
  47. return sessions, nil
  48. }
  49. // CreateUserSessionFromUsername creates a new user session.
  50. func (s *Storage) CreateUserSessionFromUsername(username, userAgent, ip string) (sessionID string, userID int64, err error) {
  51. token := rand.Text()
  52. tx, err := s.db.Begin()
  53. if err != nil {
  54. return "", 0, fmt.Errorf(`store: unable to start transaction: %v`, err)
  55. }
  56. err = tx.QueryRow(`SELECT id FROM users WHERE username = LOWER($1)`, username).Scan(&userID)
  57. if err != nil {
  58. tx.Rollback()
  59. return "", 0, fmt.Errorf(`store: unable to fetch user ID: %v`, err)
  60. }
  61. _, err = tx.Exec(
  62. `INSERT INTO user_sessions (token, user_id, user_agent, ip) VALUES ($1, $2, $3, $4)`,
  63. token,
  64. userID,
  65. userAgent,
  66. ip,
  67. )
  68. if err != nil {
  69. tx.Rollback()
  70. return "", 0, fmt.Errorf(`store: unable to create user session: %v`, err)
  71. }
  72. if err := tx.Commit(); err != nil {
  73. return "", 0, fmt.Errorf(`store: unable to commit transaction: %v`, err)
  74. }
  75. return token, userID, nil
  76. }
  77. // UserSessionByToken finds a session by the token.
  78. func (s *Storage) UserSessionByToken(token string) (*model.UserSession, error) {
  79. var session model.UserSession
  80. query := `
  81. SELECT
  82. id,
  83. user_id,
  84. token,
  85. created_at,
  86. user_agent,
  87. ip
  88. FROM
  89. user_sessions
  90. WHERE
  91. token = $1
  92. `
  93. err := s.db.QueryRow(query, token).Scan(
  94. &session.ID,
  95. &session.UserID,
  96. &session.Token,
  97. &session.CreatedAt,
  98. &session.UserAgent,
  99. &session.IP,
  100. )
  101. switch {
  102. case err == sql.ErrNoRows:
  103. return nil, nil
  104. case err != nil:
  105. return nil, fmt.Errorf(`store: unable to fetch user session: %v`, err)
  106. default:
  107. return &session, nil
  108. }
  109. }
  110. // RemoveUserSessionByToken remove a session by using the token.
  111. func (s *Storage) RemoveUserSessionByToken(userID int64, token string) error {
  112. query := `DELETE FROM user_sessions WHERE user_id=$1 AND token=$2`
  113. result, err := s.db.Exec(query, userID, token)
  114. if err != nil {
  115. return fmt.Errorf(`store: unable to remove this user session: %v`, err)
  116. }
  117. count, err := result.RowsAffected()
  118. if err != nil {
  119. return fmt.Errorf(`store: unable to remove this user session: %v`, err)
  120. }
  121. if count != 1 {
  122. return fmt.Errorf(`store: nothing has been removed`)
  123. }
  124. return nil
  125. }
  126. // RemoveUserSessionByID remove a session by using the ID.
  127. func (s *Storage) RemoveUserSessionByID(userID, sessionID int64) error {
  128. query := `DELETE FROM user_sessions WHERE user_id=$1 AND id=$2`
  129. result, err := s.db.Exec(query, userID, sessionID)
  130. if err != nil {
  131. return fmt.Errorf(`store: unable to remove this user session: %v`, err)
  132. }
  133. count, err := result.RowsAffected()
  134. if err != nil {
  135. return fmt.Errorf(`store: unable to remove this user session: %v`, err)
  136. }
  137. if count != 1 {
  138. return fmt.Errorf(`store: nothing has been removed`)
  139. }
  140. return nil
  141. }
  142. // CleanOldUserSessions removes user sessions older than specified interval (24h minimum).
  143. func (s *Storage) CleanOldUserSessions(interval time.Duration) int64 {
  144. query := `
  145. DELETE FROM
  146. user_sessions
  147. WHERE
  148. created_at < now() - $1::interval
  149. `
  150. days := max(int(interval/(24*time.Hour)), 1)
  151. result, err := s.db.Exec(query, fmt.Sprintf("%d days", days))
  152. if err != nil {
  153. return 0
  154. }
  155. n, _ := result.RowsAffected()
  156. return n
  157. }