-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
724db43
commit c73a407
Showing
6 changed files
with
175 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
package home | ||
|
||
import ( | ||
"sync" | ||
"time" | ||
) | ||
|
||
// flushAfter defines for how long will attempter be tracked. | ||
const flushAfter = 1 * time.Minute | ||
|
||
// attempter is an entry of authRateLimiter's cache. | ||
type attempter struct { | ||
until time.Time | ||
num uint16 | ||
} | ||
|
||
// authRateLimiter used to cache unsuccessful authentication attempts. | ||
type authRateLimiter struct { | ||
attempters map[string]attempter | ||
blockDur time.Duration | ||
attemptersLock sync.RWMutex | ||
maxAttempts uint16 | ||
} | ||
|
||
// newAuthRateLimiter returns properly initialized *authRateLimiter. | ||
func newAuthRateLimiter(blockDur time.Duration, maxAttempts uint16) (ab *authRateLimiter) { | ||
return &authRateLimiter{ | ||
attempters: make(map[string]attempter), | ||
blockDur: blockDur, | ||
maxAttempts: maxAttempts, | ||
} | ||
} | ||
|
||
// flushLocked checks each tracked attempter removing expired ones. For | ||
// internal use only. | ||
func (ab *authRateLimiter) flushLocked(now time.Time) { | ||
for k, v := range ab.attempters { | ||
if now.After(v.until) { | ||
delete(ab.attempters, k) | ||
} | ||
} | ||
} | ||
|
||
// flush stops tracking of attempters tracking period of which have ended. | ||
func (ab *authRateLimiter) flush() { | ||
now := time.Now() | ||
|
||
ab.attemptersLock.Lock() | ||
defer ab.attemptersLock.Unlock() | ||
|
||
ab.flushLocked(now) | ||
} | ||
|
||
// checkLocked checks the attempter for it's state. For internal use only. | ||
func (ab *authRateLimiter) checkLocked(attID string, now time.Time) (left time.Duration) { | ||
a, ok := ab.attempters[attID] | ||
if !ok { | ||
return 0 | ||
} | ||
|
||
if a.num < ab.maxAttempts { | ||
return 0 | ||
} | ||
|
||
return a.until.Sub(now) | ||
} | ||
|
||
// check returns the time left until unblocking. The nonpositive result should | ||
// be interpreted as not blocked attempter. | ||
func (ab *authRateLimiter) check(attID string) (left time.Duration) { | ||
now := time.Now() | ||
ab.flush() | ||
|
||
ab.attemptersLock.RLock() | ||
defer ab.attemptersLock.RUnlock() | ||
|
||
return ab.checkLocked(attID, now) | ||
} | ||
|
||
// incLocked increments the number of unsuccessful attempts for attempter with | ||
// ip and updates it's blocking moment if needed. For internal use only. | ||
func (ab *authRateLimiter) incLocked(attID string, now time.Time) { | ||
var until time.Time = now.Add(flushAfter) | ||
var attempts uint16 = 1 | ||
|
||
a, ok := ab.attempters[attID] | ||
if ok { | ||
// The attempter will be tracked during at least 1 minute since | ||
// very first unsuccessful attempt but not since each one. | ||
until = a.until | ||
attempts = a.num + 1 | ||
} | ||
if attempts >= ab.maxAttempts { | ||
until = now.Add(ab.blockDur) | ||
} | ||
|
||
ab.attempters[attID] = attempter{ | ||
num: attempts, | ||
until: until, | ||
} | ||
} | ||
|
||
// inc updates the tracked attempter. | ||
func (ab *authRateLimiter) inc(attID string) { | ||
now := time.Now() | ||
|
||
ab.attemptersLock.Lock() | ||
defer ab.attemptersLock.Unlock() | ||
|
||
ab.incLocked(attID, now) | ||
} | ||
|
||
// remove stops any tracking and any blocking of an attempter. | ||
func (ab *authRateLimiter) remove(attID string) { | ||
ab.attemptersLock.Lock() | ||
defer ab.attemptersLock.Unlock() | ||
|
||
delete(ab.attempters, attID) | ||
} |
Oops, something went wrong.