Add visitor phone lookup flow

This commit is contained in:
wangxuming
2026-07-15 11:26:37 +08:00
parent 331e30894b
commit 7f751bebae
21 changed files with 971 additions and 104 deletions

View File

@@ -17,6 +17,52 @@ type loginLimiter struct {
now func() time.Time
}
type queryLimitEntry struct {
windowStart time.Time
count int
}
// queryLimiter is deliberately small and in-memory for the temporary public
// phone lookup. The production replacement will be an OTP or external
// identity provider, so this limiter is only a safety net for the test flow.
type queryLimiter struct {
mu sync.Mutex
entries map[string]queryLimitEntry
now func() time.Time
limit int
window time.Duration
}
func newQueryLimiter(now func() time.Time, limit int, window time.Duration) *queryLimiter {
return &queryLimiter{
entries: make(map[string]queryLimitEntry), now: now, limit: limit, window: window,
}
}
func (l *queryLimiter) allow(key string) (bool, time.Duration) {
if l == nil || l.limit <= 0 || l.window <= 0 {
return true, 0
}
l.mu.Lock()
defer l.mu.Unlock()
now := l.now()
entry, ok := l.entries[key]
if !ok || now.Sub(entry.windowStart) >= l.window {
entry = queryLimitEntry{windowStart: now}
}
if entry.count >= l.limit {
retry := l.window - now.Sub(entry.windowStart)
if retry < 0 {
retry = 0
}
return false, retry
}
entry.count++
l.entries[key] = entry
return true, 0
}
func newLoginLimiter(now func() time.Time) *loginLimiter {
return &loginLimiter{attempts: make(map[string]loginAttempt), now: now}
}