The user_session is valid for 24 hours, but the session will be bumped if it has been over an hour since the last update. An hour was set as a deadline, so that we would not update the user_session rows too often.
119 lines
2.3 KiB
Go
119 lines
2.3 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"crypto/subtle"
|
|
"database/sql"
|
|
"errors"
|
|
"strings"
|
|
|
|
"go-backend/internal/auth"
|
|
"go-backend/internal/database/sqlc"
|
|
)
|
|
|
|
type AuthService struct {
|
|
db *sql.DB
|
|
queries *sqlc.Queries
|
|
}
|
|
|
|
func NewAuthService(db *sql.DB, queries *sqlc.Queries) *AuthService {
|
|
return &AuthService{
|
|
db: db,
|
|
queries: queries,
|
|
}
|
|
}
|
|
|
|
type SessionWithToken struct {
|
|
Session sqlc.UserSession
|
|
Token string
|
|
}
|
|
|
|
func (s *AuthService) CreateSession(ctx context.Context, userID string) (*SessionWithToken, error) {
|
|
id, err := auth.GenerateSecureRandomString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
secret, err := auth.GenerateSecureRandomString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
secretHash := auth.HashSecret(secret)
|
|
token := id + "." + secret
|
|
|
|
session, err := s.queries.InsertSession(ctx, sqlc.InsertSessionParams{
|
|
ID: id,
|
|
SecretHash: secretHash,
|
|
UserID: userID,
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &SessionWithToken{
|
|
Session: session,
|
|
Token: token,
|
|
}, nil
|
|
|
|
}
|
|
|
|
func (s *AuthService) ValidateSessionToken(ctx context.Context, token string) (*sqlc.UserSession, bool, error) {
|
|
tokenParts := strings.Split(token, ".")
|
|
if len(tokenParts) != 2 {
|
|
return nil, false, nil
|
|
}
|
|
|
|
sessionID := tokenParts[0]
|
|
sessionSecret := tokenParts[1]
|
|
|
|
session, err := s.queries.SelectSessionById(ctx, sessionID)
|
|
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return nil, false, nil
|
|
}
|
|
|
|
return nil, false, err
|
|
}
|
|
|
|
if auth.CheckExpiration(session.LastVerifiedAt) {
|
|
err = s.queries.DeleteSessionById(ctx, sessionID)
|
|
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
return nil, false, nil
|
|
}
|
|
|
|
tokenSecretHash := auth.HashSecret(sessionSecret)
|
|
if subtle.ConstantTimeCompare(tokenSecretHash, session.SecretHash) != 1 {
|
|
return nil, false, nil
|
|
}
|
|
|
|
if auth.CheckNeedForBump(session.LastVerifiedAt) {
|
|
session, err = s.queries.UpdateSessionVerifiedAt(ctx, sessionID)
|
|
|
|
if err != nil {
|
|
return nil, false, err
|
|
}
|
|
|
|
return &session, true, nil
|
|
}
|
|
|
|
return &session, false, nil
|
|
}
|
|
|
|
func (s *AuthService) DeleteSession(ctx context.Context, token string) error {
|
|
tokenParts := strings.Split(token, ".")
|
|
if len(tokenParts) != 2 {
|
|
return nil
|
|
}
|
|
|
|
sessionID := tokenParts[0]
|
|
|
|
err := s.queries.DeleteSessionById(ctx, sessionID)
|
|
|
|
return err
|
|
}
|