57aec2c6b3
- Session and email verification/reset tokens stored as SHA-256 hash in DB (raw token stays client-side in cookie/email link) - Tauri CSP set: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' wss: https: - escapeHtml now handles double and single quotes to prevent attribute-based XSS
66 lines
1.6 KiB
Go
66 lines
1.6 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"database/sql"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/config"
|
|
)
|
|
|
|
type SessionStore struct {
|
|
db *sql.DB
|
|
cfg *config.Config
|
|
}
|
|
|
|
func NewSessionStore(db *sql.DB, cfg *config.Config) *SessionStore {
|
|
return &SessionStore{db: db, cfg: cfg}
|
|
}
|
|
|
|
// hashToken computes a SHA-256 hash of a token string.
|
|
// Tokens are stored hashed in the DB so a DB leak doesn't expose active sessions.
|
|
func hashToken(token string) string {
|
|
h := sha256.Sum256([]byte(token))
|
|
return hex.EncodeToString(h[:])
|
|
}
|
|
|
|
func (s *SessionStore) Create(ctx context.Context, userID string) (string, error) {
|
|
b := make([]byte, 32)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", fmt.Errorf("generate token: %w", err)
|
|
}
|
|
token := hex.EncodeToString(b)
|
|
tokenHash := hashToken(token)
|
|
|
|
_, err := s.db.ExecContext(ctx, `
|
|
INSERT INTO sessions (user_id, token, expires_at)
|
|
VALUES ($1, $2, $3)
|
|
`, userID, tokenHash, time.Now().Add(s.cfg.Session.Duration))
|
|
if err != nil {
|
|
return "", fmt.Errorf("insert session: %w", err)
|
|
}
|
|
|
|
return token, nil
|
|
}
|
|
|
|
func (s *SessionStore) GetUserIDByToken(ctx context.Context, token string) (string, error) {
|
|
var userID string
|
|
err := s.db.QueryRowContext(ctx, `
|
|
SELECT user_id FROM sessions
|
|
WHERE token = $1 AND expires_at > NOW()
|
|
`, hashToken(token)).Scan(&userID)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return userID, nil
|
|
}
|
|
|
|
func (s *SessionStore) Delete(ctx context.Context, token string) error {
|
|
_, err := s.db.ExecContext(ctx, `DELETE FROM sessions WHERE token = $1`, hashToken(token))
|
|
return err
|
|
}
|