mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-18 00:34:28 +08:00
limit the maximum count of password / token check failures per IP/user per minute (#33)
This commit is contained in:
@@ -8,4 +8,6 @@ type DuplicateChecker interface {
|
||||
SetSubmissionRemark(checkerType DuplicateCheckerType, uid int64, identification string, remark string)
|
||||
GetOrSetCronJobRunningInfo(jobName string, runningInfo string, runningInterval time.Duration) (bool, string)
|
||||
RemoveCronJobRunningInfo(jobName string)
|
||||
GetFailureCount(failureKey string) uint32
|
||||
IncreaseFailureCount(failureKey string) uint32
|
||||
}
|
||||
|
||||
@@ -48,3 +48,13 @@ func (c *DuplicateCheckerContainer) GetOrSetCronJobRunningInfo(jobName string, r
|
||||
func (c *DuplicateCheckerContainer) RemoveCronJobRunningInfo(jobName string) {
|
||||
c.Current.RemoveCronJobRunningInfo(jobName)
|
||||
}
|
||||
|
||||
// GetFailureCount returns the failure count of the specified failure key
|
||||
func (c *DuplicateCheckerContainer) GetFailureCount(failureKey string) uint32 {
|
||||
return c.Current.GetFailureCount(failureKey)
|
||||
}
|
||||
|
||||
// IncreaseFailureCount increases the failure count of the specified failure key
|
||||
func (c *DuplicateCheckerContainer) IncreaseFailureCount(failureKey string) uint32 {
|
||||
return c.Current.IncreaseFailureCount(failureKey)
|
||||
}
|
||||
|
||||
@@ -12,4 +12,5 @@ const (
|
||||
DUPLICATE_CHECKER_TYPE_NEW_TEMPLATE DuplicateCheckerType = 4
|
||||
DUPLICATE_CHECKER_TYPE_NEW_PICTURE DuplicateCheckerType = 5
|
||||
DUPLICATE_CHECKER_TYPE_IMPORT_TRANSACTIONS DuplicateCheckerType = 6
|
||||
DUPLICATE_CHECKER_TYPE_FAILURE_CHECK DuplicateCheckerType = 255
|
||||
)
|
||||
|
||||
@@ -69,6 +69,34 @@ func (c *InMemoryDuplicateChecker) RemoveCronJobRunningInfo(jobName string) {
|
||||
c.cache.Delete(c.getCacheKey(DUPLICATE_CHECKER_TYPE_BACKGROUND_CRON_JOB, 0, jobName))
|
||||
}
|
||||
|
||||
// GetFailureCount returns the failure count of the specified failure key
|
||||
func (c *InMemoryDuplicateChecker) GetFailureCount(failureKey string) uint32 {
|
||||
existedFailureCount, found := c.cache.Get(c.getCacheKey(DUPLICATE_CHECKER_TYPE_FAILURE_CHECK, 0, failureKey))
|
||||
|
||||
if found {
|
||||
return existedFailureCount.(uint32)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// IncreaseFailureCount increases the failure count of the specified failure key
|
||||
func (c *InMemoryDuplicateChecker) IncreaseFailureCount(failureKey string) uint32 {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
cacheKey := c.getCacheKey(DUPLICATE_CHECKER_TYPE_FAILURE_CHECK, 0, failureKey)
|
||||
_, found := c.cache.Get(cacheKey)
|
||||
|
||||
if found {
|
||||
failureCount, _ := c.cache.IncrementUint32(cacheKey, uint32(1))
|
||||
return failureCount
|
||||
} else {
|
||||
c.cache.Set(cacheKey, uint32(1), 1*time.Minute)
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
func (c *InMemoryDuplicateChecker) getCacheKey(checkerType DuplicateCheckerType, uid int64, identification string) string {
|
||||
return fmt.Sprintf("%d|%d|%s", checkerType, uid, identification)
|
||||
}
|
||||
|
||||
@@ -155,3 +155,77 @@ func TestGetOrSetRunningInfoConcurrent(t *testing.T) {
|
||||
|
||||
assert.Equal(t, uint32(999), setRunningInfoCount.Load())
|
||||
}
|
||||
|
||||
func TestGetFailureCount(t *testing.T) {
|
||||
checker, _ := NewInMemoryDuplicateChecker(&settings.Config{
|
||||
DuplicateSubmissionsIntervalDuration: time.Second,
|
||||
InMemoryDuplicateCheckerCleanupIntervalDuration: time.Second,
|
||||
})
|
||||
|
||||
failureKey := "127.0.0.1"
|
||||
|
||||
failureCount := checker.GetFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(0), failureCount)
|
||||
|
||||
failureCount = checker.IncreaseFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(1), failureCount)
|
||||
|
||||
failureCount = checker.GetFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(1), failureCount)
|
||||
}
|
||||
|
||||
func TestIncreaseFailureCount(t *testing.T) {
|
||||
checker, _ := NewInMemoryDuplicateChecker(&settings.Config{
|
||||
DuplicateSubmissionsIntervalDuration: time.Second,
|
||||
InMemoryDuplicateCheckerCleanupIntervalDuration: time.Second,
|
||||
})
|
||||
|
||||
failureKey := "127.0.0.1"
|
||||
|
||||
failureCount := checker.IncreaseFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(1), failureCount)
|
||||
|
||||
failureCount = checker.GetFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(1), failureCount)
|
||||
|
||||
failureCount = checker.IncreaseFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(2), failureCount)
|
||||
|
||||
failureCount = checker.GetFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(2), failureCount)
|
||||
|
||||
failureCount = checker.IncreaseFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(3), failureCount)
|
||||
|
||||
failureCount = checker.GetFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(3), failureCount)
|
||||
}
|
||||
|
||||
func TestIncreaseFailureCountConcurrent(t *testing.T) {
|
||||
checker, _ := NewInMemoryDuplicateChecker(&settings.Config{
|
||||
DuplicateSubmissionsIntervalDuration: time.Second,
|
||||
InMemoryDuplicateCheckerCleanupIntervalDuration: time.Second,
|
||||
})
|
||||
|
||||
failureKey := "127.0.0.1"
|
||||
|
||||
concurrentCount := 10
|
||||
var waitGroup sync.WaitGroup
|
||||
|
||||
for routineIndex := 0; routineIndex < concurrentCount; routineIndex++ {
|
||||
waitGroup.Add(1)
|
||||
|
||||
go func(currentRoutineIndex int) {
|
||||
for cycle := 0; cycle < 10; cycle++ {
|
||||
checker.IncreaseFailureCount(failureKey)
|
||||
}
|
||||
|
||||
waitGroup.Done()
|
||||
}(routineIndex)
|
||||
}
|
||||
|
||||
waitGroup.Wait()
|
||||
|
||||
failureCount := checker.GetFailureCount(failureKey)
|
||||
assert.Equal(t, uint32(100), failureCount)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user