| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 | const AbstractClientStore = require('express-brute/lib/AbstractClientStore')const KnexStore = module.exports = function (options) {  options = options || Object.create(null)  AbstractClientStore.apply(this, arguments)  this.options = Object.assign(Object.create(null), KnexStore.defaults, options)  if (this.options.knex) {    this.knex = this.options.knex  } else {    this.knex = require('knex')(KnexStore.defaultsKnex)  }  if (options.createTable === false) {    this.ready = Promise.resolve()  } else {    this.ready = this.knex.schema.hasTable(this.options.tablename)      .then((exists) => {        if (exists) {          return        }        return this.knex.schema.createTable(this.options.tablename, (table) => {          table.string('key')          table.bigInteger('firstRequest').nullable()          table.bigInteger('lastRequest').nullable()          table.bigInteger('lifetime').nullable()          table.integer('count')        })      })  }}KnexStore.prototype = Object.create(AbstractClientStore.prototype)KnexStore.prototype.set = async function (key, value, lifetime, callback) {  try {    lifetime = lifetime || 0    await this.ready    const resp = await this.knex.transaction((trx) => {      return trx        .select('*')        .forUpdate()        .from(this.options.tablename)        .where('key', '=', key)        .then((foundKeys) => {          if (foundKeys.length === 0) {            return trx.from(this.options.tablename)              .insert({                key: key,                lifetime: new Date(Date.now() + lifetime * 1000).getTime(),                lastRequest: new Date(value.lastRequest).getTime(),                firstRequest: new Date(value.firstRequest).getTime(),                count: value.count              })          } else {            return trx(this.options.tablename)              .where('key', '=', key)              .update({                lifetime: new Date(Date.now() + lifetime * 1000).getTime(),                count: value.count,                lastRequest: new Date(value.lastRequest).getTime()              })          }        })    })    callback(null, resp)  } catch (err) {    callback(err, null)  }}KnexStore.prototype.get = async function (key, callback) {  try {    await this.ready    await this.clearExpired()    const resp = await this.knex.select('*')      .from(this.options.tablename)      .where('key', '=', key)    let o = null    if (resp[0]) {      o = {}      o.lastRequest = new Date(resp[0].lastRequest)      o.firstRequest = new Date(resp[0].firstRequest)      o.count = resp[0].count    }    callback(null, o)  } catch (err) {    callback(err, null)  }}KnexStore.prototype.reset = async function (key, callback) {  try {    await this.ready    const resp = await this.knex(this.options.tablename)      .where('key', '=', key)      .del()    callback(null, resp)  } catch (err) {    callback(err, null)  }}KnexStore.prototype.increment = async function (key, lifetime, callback) {  try {    const result = await this.get(key)    let resp = null    if (result) {      resp = await this.knex(this.options.tablename)        .increment('count', 1)        .where('key', '=', key)    } else {      resp = await this.knex(this.options.tablename)        .insert({          key: key,          firstRequest: new Date().getTime(),          lastRequest: new Date().getTime(),          lifetime: new Date(Date.now() + lifetime * 1000).getTime(),          count: 1        })    }    callback(null, resp)  } catch (err) {    callback(err, null)  }}KnexStore.prototype.clearExpired = async function (callback) {  await this.ready  return this.knex(this.options.tablename)    .del()    .where('lifetime', '<', new Date().getTime())}KnexStore.defaults = {  tablename: 'brute',  createTable: true}KnexStore.defaultsKnex = {  client: 'sqlite3',  // debug: true,  connection: {    filename: './brute-knex.sqlite'  }}
 |