user_session.go 4.1 KB

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