internal/repository/oauth_code_postgres.go
Rama main · réplica de lectura del repositorio original.
package repository
import (
"context"
"fmt"
"time"
"xprem/internal/database"
"xprem/internal/database/postgres/pgdb"
"github.com/jackc/pgx/v5/pgtype"
)
// OAuthAuthorizationCode is the consent context a consumed code was frozen
// with; the token exchange verifies the request against it.
type OAuthAuthorizationCode struct {
ID string
ClientID string
UserID string
RedirectURI string
CodeChallenge string
Scope string
ExpiresAt time.Time
}
type InsertOAuthAuthorizationCodeParameters struct {
ID string
ClientID string
UserID string
RedirectURI string
CodeChallenge string
Scope string
ExpiresAt time.Time
}
type PostgresOAuthCodeRepository struct {
engine *database.Engine
}
func NewPostgresOAuthCodeRepository(engine *database.Engine) *PostgresOAuthCodeRepository {
return &PostgresOAuthCodeRepository{
engine: engine,
}
}
func (s *PostgresOAuthCodeRepository) InsertOAuthAuthorizationCode(ctx context.Context, params InsertOAuthAuthorizationCodeParameters) error {
if err := s.engine.Queries.InsertOAuthAuthorizationCode(ctx, pgdb.InsertOAuthAuthorizationCodeParams{
ID: ToPgUUID(params.ID),
ClientID: ToPgUUID(params.ClientID),
UserID: ToPgUUID(params.UserID),
RedirectUri: params.RedirectURI,
CodeChallenge: params.CodeChallenge,
Scope: params.Scope,
ExpiresAt: pgtype.Timestamptz{Time: params.ExpiresAt.UTC(), Valid: true},
}); err != nil {
return fmt.Errorf("failed to insert oauth authorization code into database: %w", err)
}
return nil
}
// ConsumeOAuthAuthorizationCode claims a code, atomically and exactly once.
// ErrResourceNotFound means it was not claimable: unknown, expired, or
// already exchanged.
func (s *PostgresOAuthCodeRepository) ConsumeOAuthAuthorizationCode(ctx context.Context, id string) (OAuthAuthorizationCode, error) {
row, err := s.engine.Queries.ConsumeOAuthAuthorizationCode(ctx, ToPgUUID(id))
if err != nil {
if database.IsNoRows(err) {
return OAuthAuthorizationCode{}, &ErrResourceNotFound{Resource: "oauth authorization code", Identifier: id}
}
return OAuthAuthorizationCode{}, fmt.Errorf("failed to consume oauth authorization code in database: %w", err)
}
return OAuthAuthorizationCode{
ID: row.ID.String(),
ClientID: row.ClientID.String(),
UserID: row.UserID.String(),
RedirectURI: row.RedirectUri,
CodeChallenge: row.CodeChallenge,
Scope: row.Scope,
ExpiresAt: row.ExpiresAt.Time,
}, nil
}
// DeleteExpiredOAuthAuthorizationCodes purges dead codes; called inline when a
// new one is minted, which keeps the table bounded without a background job.
func (s *PostgresOAuthCodeRepository) DeleteExpiredOAuthAuthorizationCodes(ctx context.Context) error {
if err := s.engine.Queries.DeleteExpiredOAuthAuthorizationCodes(ctx); err != nil {
return fmt.Errorf("failed to delete expired oauth authorization codes from database: %w", err)
}
return nil
}