Added limit on wrong password

This commit is contained in:
Kasra Bigdeli
2019-08-13 21:43:20 -04:00
parent a21a070892
commit cd28300015
4 changed files with 88 additions and 0 deletions

View File

@@ -45,6 +45,7 @@ class ApiStatusCodes {
static readonly ILLEGAL_PARAMETER = 1110
static readonly NOT_FOUND = 1111
static readonly AUTHENTICATION_FAILED = 1112
static readonly STATUS_PASSWORD_BACK_OFF = 1113
}
export = ApiStatusCodes

View File

@@ -6,9 +6,12 @@ import InjectionExtractor = require('../../injection/InjectionExtractor')
import DataStoreProvider = require('../../datastore/DataStoreProvider')
import CaptainManager = require('../../user/system/CaptainManager')
import Authenticator = require('../../user/Authenticator')
import CircularQueue from '../../utils/CircularQueue'
const router = express.Router()
const failedLoginCircularTimestamps = new CircularQueue<number>(5)
router.post('/', function(req, res, next) {
let password = req.body.password || ''
@@ -30,6 +33,16 @@ router.post('/', function(req, res, next) {
Promise.resolve() //
.then(function() {
const oldestKnownFailedLogin = failedLoginCircularTimestamps.peek()
if (
oldestKnownFailedLogin &&
new Date().getTime() - oldestKnownFailedLogin < 30000
)
throw ApiStatusCodes.createError(
ApiStatusCodes.STATUS_PASSWORD_BACK_OFF,
'Too many wrong passwords... Wait for 30 seconds and retry.'
)
return DataStoreProvider.getDataStore(namespace).getHashedPassword()
})
.then(function(savedHashedPassword) {
@@ -54,6 +67,19 @@ router.post('/', function(req, res, next) {
baseApi.data = { token: authToken }
res.send(baseApi)
})
.catch(function(err) {
return new Promise(function(resolve, reject) {
if (
err &&
err.captainErrorType &&
err.captainErrorType ===
ApiStatusCodes.STATUS_WRONG_PASSWORD
) {
failedLoginCircularTimestamps.push(new Date().getTime())
}
reject(err)
})
})
.catch(ApiStatusCodes.createCatcher(res))
})

View File

@@ -0,0 +1,23 @@
export default class CircularQueue<T> {
private values: (T | undefined)[] = []
private currSize = 0
constructor(private maxSize: number) {
if (!this.maxSize) throw new Error('invalid size of zero')
if (this.maxSize === 1) throw new Error('invalid size of one')
for (let index = 0; index < this.maxSize; index++) {
this.values.push(undefined)
}
}
push(value: T) {
this.values[this.currSize % this.maxSize] = value
this.currSize++
}
peek(): T | undefined {
const nextPositionToBeOverwritten = this.currSize % this.maxSize
return this.values[nextPositionToBeOverwritten]
}
}

View File

@@ -0,0 +1,38 @@
import CircularQueue from '../src/utils/CircularQueue'
function createTest(size: number, initWith: number) {
const testQueue = new CircularQueue<string>(size)
for (let index = 0; index < initWith; index++) {
testQueue.push('val:' + (index + 1))
}
return testQueue
}
test('Large Circular Queue', () => {
for (let index = 5; index < 20; index++) {
expect(createTest(4, index).peek()) //
.toBe('val:' + (index - 3))
}
})
test('Basic Circular Queue', () => {
expect(createTest(2, 10).peek()) //
.toBe('val:9')
})
test('Basic Circular Queue', () => {
expect(createTest(2, 1).peek()) //
.toBe(undefined)
})
test('Basic Circular Queue', () => {
expect(createTest(2, 2).peek()) //
.toBe('val:1')
})
test('Basic Circular Queue', () => {
expect(createTest(2, 3).peek()) //
.toBe('val:2')
})