Sovite.Abuse.Penalty (sovite v0.2.0)

Copy Markdown View Source

Counts failures per key (for example failed logins per client address) and bans a key for a while after too many of them.

children = [
  {Sovite.Abuse.Penalty, name: MyApp.AuthPenalty, max_failures: 5, window: 600_000, ban_time: 3_600_000}
]

Penalty.banned?(MyApp.AuthPenalty, ip)
Penalty.failure(MyApp.AuthPenalty, ip)

A key with :max_failures failures within :window milliseconds is banned for :ban_time milliseconds. Successes do not reset the count, so an attacker who owns one account cannot use it to keep guessing others.

banned?/2 reads an ETS table and never waits on the process, so it is cheap to call on every connection. State is in memory: a restart forgets all bans.

Options

  • :name - an atom, also used as the ETS table name. Required.
  • :max_failures - required.
  • :window - milliseconds. Required.
  • :ban_time - milliseconds. Required.
  • :cleanup_interval - milliseconds between purges of old entries. Defaults to one minute.

Telemetry

  • [:sovite, :abuse, :penalty, :banned] - %{failures}, %{penalty, key, ban_time}, when a key gets banned.

Summary

Functions

Returns whether key is banned now.

Records a failure for key. Returns :banned if key is banned now.

Forgets key, lifting any ban.

Starts the counter.

Functions

banned?(name, key)

@spec banned?(atom(), term()) :: boolean()

Returns whether key is banned now.

failure(name, key)

@spec failure(atom(), term()) :: :ok | :banned

Records a failure for key. Returns :banned if key is banned now.

reset(name, key)

@spec reset(atom(), term()) :: :ok

Forgets key, lifting any ban.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts the counter.