2024-09-22 08:26:27 +00:00
|
|
|
package authrequest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/internal/model"
|
2024-10-06 09:28:26 +00:00
|
|
|
"git.faercol.me/faercol/polyculeconnect/polyculeconnect/logger"
|
2024-09-22 08:26:27 +00:00
|
|
|
"github.com/google/uuid"
|
|
|
|
)
|
|
|
|
|
|
|
|
var ErrNotFound = errors.New("backend not found")
|
|
|
|
|
2024-10-06 20:11:58 +00:00
|
|
|
const authRequestRows = `"id", "client_id", "backend_id", "scopes", "redirect_uri", "state", "nonce", "response_type", "creation_time", "done"`
|
2024-09-22 08:26:27 +00:00
|
|
|
|
|
|
|
type AuthRequestDB interface {
|
|
|
|
GetAuthRequestByID(ctx context.Context, id uuid.UUID) (*model.AuthRequest, error)
|
|
|
|
CreateAuthRequest(ctx context.Context, req model.AuthRequest) error
|
2024-10-06 20:11:58 +00:00
|
|
|
ValidateAuthRequest(ctx context.Context, reqID uuid.UUID) error
|
2024-09-22 08:26:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type sqlAuthRequestDB struct {
|
|
|
|
db *sql.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *sqlAuthRequestDB) GetAuthRequestByID(ctx context.Context, id uuid.UUID) (*model.AuthRequest, error) {
|
2024-10-06 09:28:26 +00:00
|
|
|
logger.L.Debugf("Getting auth request with id %s", id)
|
2024-09-22 08:26:27 +00:00
|
|
|
query := fmt.Sprintf(`SELECT %s FROM "auth_request_2" WHERE "id" = ?`, authRequestRows)
|
|
|
|
row := db.db.QueryRowContext(ctx, query, id)
|
|
|
|
|
|
|
|
var res model.AuthRequest
|
|
|
|
var scopesStr []byte
|
|
|
|
|
2024-10-06 20:11:58 +00:00
|
|
|
fmt.Println(query)
|
|
|
|
if err := row.Scan(&res.ID, &res.ClientID, &res.BackendID, &scopesStr, &res.RedirectURI, &res.State, &res.Nonce, &res.ResponseType, &res.CreationDate, &res.DoneVal); err != nil {
|
2024-09-22 08:26:27 +00:00
|
|
|
return nil, fmt.Errorf("failed to get auth request from DB: %w", err)
|
|
|
|
}
|
|
|
|
if err := json.Unmarshal(scopesStr, &res.Scopes); err != nil {
|
|
|
|
return nil, fmt.Errorf("invalid format for scopes: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &res, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *sqlAuthRequestDB) CreateAuthRequest(ctx context.Context, req model.AuthRequest) error {
|
2024-10-06 09:28:26 +00:00
|
|
|
logger.L.Debugf("Creating a new auth request between client app %s and backend %s", req.ClientID, req.BackendID)
|
2024-09-22 08:26:27 +00:00
|
|
|
tx, err := db.db.BeginTx(ctx, nil)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to start transaction: %w", err)
|
|
|
|
}
|
|
|
|
defer func() { _ = tx.Rollback() }()
|
|
|
|
|
|
|
|
scopesStr, err := json.Marshal(req.Scopes)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to serialize scopes: %w", err)
|
|
|
|
}
|
|
|
|
|
2024-10-06 09:28:26 +00:00
|
|
|
// TODO: when the old table is done, rename into auth_request
|
2024-10-06 20:11:58 +00:00
|
|
|
query := fmt.Sprintf(`INSERT INTO "auth_request_2" (%s) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, authRequestRows)
|
2024-09-22 08:26:27 +00:00
|
|
|
_, err = tx.ExecContext(ctx, query,
|
|
|
|
req.ID, req.ClientID, req.BackendID,
|
|
|
|
scopesStr, req.RedirectURI, req.State,
|
2024-10-06 20:11:58 +00:00
|
|
|
req.Nonce, req.ResponseType, req.CreationDate, false,
|
2024-09-22 08:26:27 +00:00
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to insert in DB: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
|
|
return fmt.Errorf("failed to commit transaction: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-10-06 20:11:58 +00:00
|
|
|
func (db *sqlAuthRequestDB) ValidateAuthRequest(ctx context.Context, reqID uuid.UUID) error {
|
|
|
|
logger.L.Debugf("Validating auth request %s", reqID)
|
|
|
|
tx, err := db.db.BeginTx(ctx, nil)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to start transaction: %w", err)
|
|
|
|
}
|
|
|
|
defer func() { _ = tx.Rollback() }()
|
|
|
|
|
|
|
|
res, err := tx.ExecContext(ctx, `UPDATE "auth_request_2" SET done = true WHERE id = $1`, reqID.String())
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to update in DB: %w", err)
|
|
|
|
}
|
|
|
|
affectedRows, err := res.RowsAffected()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to check number of affected rows: %w", err)
|
|
|
|
}
|
|
|
|
if affectedRows != 1 {
|
|
|
|
return ErrNotFound
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := tx.Commit(); err != nil {
|
|
|
|
return fmt.Errorf("failed to commit transaction: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-09-22 08:26:27 +00:00
|
|
|
func New(db *sql.DB) *sqlAuthRequestDB {
|
|
|
|
return &sqlAuthRequestDB{db: db}
|
|
|
|
}
|