mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-11-13 22:46:18 +00:00
fix: audit fixes for websearch, notifications, and channel pricing
P0: fix wildcard matching test assertion (config order, not longest prefix) P0: add TotalRecharged to auth cache snapshot (v5) for percentage threshold P1: move pricing rules into per-platform sections in ChannelsView P1: populate account name cache when editing existing channel rules P1: sanitize email subject headers to prevent SMTP injection P1: make Redis INCR+EXPIRE idempotent for rate limiting P1: deep copy FeaturesConfig in Channel.Clone() P2: clean up stale email="" placeholder comments P2: replace log.Printf with slog in email_service.go
This commit is contained in:
1 parent
a68df457d8
commit
b7fb2e4387
13 files changed
+273
-118
No files matched your search
@@ -3,6 +3,7 @@ package repository
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/service"
|
||||
@@ -10,10 +11,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
verifyCodeKeyPrefix = "verify_code:"
|
||||
notifyVerifyKeyPrefix = "notify_verify:"
|
||||
passwordResetKeyPrefix = "password_reset:"
|
||||
passwordResetSentAtKeyPrefix = "password_reset_sent:"
|
||||
verifyCodeKeyPrefix = "verify_code:"
|
||||
notifyVerifyKeyPrefix = "notify_verify:"
|
||||
passwordResetKeyPrefix = "password_reset:"
|
||||
passwordResetSentAtKeyPrefix = "password_reset_sent:"
|
||||
notifyCodeUserRateKeyPrefix = "notify_code_user_rate:"
|
||||
)
|
||||
|
||||
// verifyCodeKey generates the Redis key for email verification code.
|
||||
@@ -141,3 +143,31 @@ func (c *emailCache) DeleteNotifyVerifyCode(ctx context.Context, email string) e
|
||||
key := notifyVerifyKey(email)
|
||||
return c.rdb.Del(ctx, key).Err()
|
||||
}
|
||||
|
||||
// User-level rate limiting for notify email verification codes
|
||||
|
||||
func notifyCodeUserRateKey(userID int64) string {
|
||||
return notifyCodeUserRateKeyPrefix + fmt.Sprintf("%d", userID)
|
||||
}
|
||||
|
||||
func (c *emailCache) IncrNotifyCodeUserRate(ctx context.Context, userID int64, window time.Duration) (int64, error) {
|
||||
key := notifyCodeUserRateKey(userID)
|
||||
count, err := c.rdb.Incr(ctx, key).Result()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Always set TTL (idempotent) to avoid orphan keys if process crashes between INCR and EXPIRE.
|
||||
if err := c.rdb.Expire(ctx, key, window).Err(); err != nil {
|
||||
return count, fmt.Errorf("expire notify code rate key: %w", err)
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *emailCache) GetNotifyCodeUserRate(ctx context.Context, userID int64) (int64, error) {
|
||||
key := notifyCodeUserRateKey(userID)
|
||||
count, err := c.rdb.Get(ctx, key).Int64()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
Reference in new issue
Block a user