66 lines
2.4 KiB
Go
66 lines
2.4 KiB
Go
package payment
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"log/slog"
|
|
"strings"
|
|
|
|
dbent "github.com/Wei-Shaw/sub2api/ent"
|
|
"github.com/Wei-Shaw/sub2api/internal/config"
|
|
"github.com/google/wire"
|
|
)
|
|
|
|
// EncryptionKey is a named type for the payment encryption key (AES-256, 32 bytes).
|
|
// Using a named type avoids Wire ambiguity with other []byte parameters.
|
|
type EncryptionKey []byte
|
|
|
|
// ProvideEncryptionKey derives the payment encryption key from the TOTP encryption key in config.
|
|
// When the key is empty, nil is returned (payment features that need encryption will be disabled).
|
|
// When the key is non-empty but invalid (bad hex or wrong length), an error is returned
|
|
// to prevent startup with a misconfigured encryption key.
|
|
func ProvideEncryptionKey(cfg *config.Config) (EncryptionKey, error) {
|
|
if cfg == nil {
|
|
slog.Warn("payment encryption key not configured — encrypted payment config and resume signing will be unavailable")
|
|
return nil, nil
|
|
}
|
|
keyHex := strings.TrimSpace(cfg.Totp.EncryptionKey)
|
|
if keyHex == "" {
|
|
slog.Warn("payment encryption key not configured — encrypted payment config will be unavailable")
|
|
return nil, nil
|
|
}
|
|
// Reject auto-generated TOTP keys for payment signing.
|
|
// They change across restarts/instances and can silently break resume-token flows.
|
|
if !cfg.Totp.EncryptionKeyConfigured {
|
|
slog.Warn("payment encryption/signing key is not explicitly configured; set TOTP_ENCRYPTION_KEY to enable payment resume tokens")
|
|
return nil, nil
|
|
}
|
|
key, err := hex.DecodeString(keyHex)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("invalid payment encryption key (hex decode): %w", err)
|
|
}
|
|
if len(key) != 32 {
|
|
return nil, fmt.Errorf("payment encryption key must be 32 bytes, got %d", len(key))
|
|
}
|
|
return EncryptionKey(key), nil
|
|
}
|
|
|
|
// ProvideRegistry creates an empty payment provider registry.
|
|
// Providers are registered at runtime after application startup.
|
|
func ProvideRegistry() *Registry {
|
|
return NewRegistry()
|
|
}
|
|
|
|
// ProvideDefaultLoadBalancer creates a DefaultLoadBalancer backed by the ent client.
|
|
func ProvideDefaultLoadBalancer(client *dbent.Client, key EncryptionKey) *DefaultLoadBalancer {
|
|
return NewDefaultLoadBalancer(client, []byte(key))
|
|
}
|
|
|
|
// ProviderSet is the Wire provider set for the payment package.
|
|
var ProviderSet = wire.NewSet(
|
|
ProvideEncryptionKey,
|
|
ProvideRegistry,
|
|
ProvideDefaultLoadBalancer,
|
|
wire.Bind(new(LoadBalancer), new(*DefaultLoadBalancer)),
|
|
)
|