Improve CORS origin handling; extend invoice repo/service and payments dispatch; rate limit and nginx config updates

Made-with: Love
This commit is contained in:
2026-04-29 05:44:59 +00:00
parent 2cb17df4c5
commit a01797e9b2
12 changed files with 224 additions and 35 deletions

View File

@@ -43,9 +43,20 @@ var (
ErrUsernameTaken = errors.New("username taken")
ErrInvalidYears = errors.New("invalid years")
ErrLifetimeAccess = errors.New("user already has lifetime access")
// Deprecated: Create no longer returns this; an existing unpaid invoice is returned instead.
ErrPendingInvoiceExists = errors.New("pending unpaid invoice already exists")
)
func pendingMatchesRequest(p *PendingInvoice, req CreateRequest) bool {
if p.SubscriptionType != req.SubscriptionType {
return false
}
if req.SubscriptionType == user.SubYearly {
return p.Years == req.Years
}
return true
}
// Create computes amount, calls LNbits, persists pending invoice. Detects renewal.
func (s *Service) Create(ctx context.Context, req CreateRequest) (*PendingInvoice, error) {
if !req.SubscriptionType.Valid() {
@@ -62,12 +73,19 @@ func (s *Service) Create(ctx context.Context, req CreateRequest) (*PendingInvoic
req.Years = 0
}
hasPendingPubkey, err := s.repo.HasUnpaidForPubkey(ctx, req.Pubkey)
pendingExisting, err := s.repo.GetActiveUnpaidByPubkey(ctx, req.Pubkey)
if err != nil {
return nil, err
}
if hasPendingPubkey {
return nil, ErrPendingInvoiceExists
if pendingExisting != nil {
if pendingMatchesRequest(pendingExisting, req) {
// Idempotent resume: same Bolt11 until paid or LN invoice expiry.
return pendingExisting, nil
}
// Replace pending Bolt11 with one for the newly requested plan.
if err := s.repo.DeleteActiveUnpaidForPubkey(ctx, req.Pubkey); err != nil {
return nil, err
}
}
username := user.NormalizeUsername(req.Username)