fix: локальное время в уведомлениях (NOTIFY_TZ) и антидубль Accepted
- notification_date: NOTIFY_TZ → DAILY_REPORT_TZ → date процесса - SSH_ACCEPT_NOTIFY_DEDUP_SEC: пауза между Telegram для той же пары user+IP - версия 0.9.5.2, README и conf.example
This commit is contained in:
@@ -24,7 +24,7 @@ Bash-скрипт мониторинга **SSH**, **SUDO** и событий **`
|
||||
- `BACKUP_WEBHOOK_URL` — резервная доставка JSON `{"text":"..."}` (например Slack Incoming Webhook), если каналы из **`NOTIFY_CHAIN`** недоступны или вернули ошибку; **не заменяет** обязательность хотя бы одного основного канала (см. шаг 3)
|
||||
- `LOG_FILE`, `LAST_HEARTBEAT_FILE`, `LAST_REPORT_FILE`, `LAST_SSH_CHECK_FILE`, `LAST_SUDO_CHECK_FILE`, `LAST_SECURITY_EVENTS_FILE`, `LAST_LOGIND_CHECK_FILE`, `BAN_LIST_FILE`
|
||||
- `ENABLE_LOGIND_MONITOR`, `LOGIND_NOTIFY_NEW`, `LOGIND_NOTIFY_REMOVED`, `LOGIND_NOTIFY_FAILED`, `LOGIND_SKIP_REMOTE` — см. раздел «Мониторинг systemd-logind» ниже
|
||||
- `DAILY_REPORT_HOUR` (0..23), `DAILY_REPORT_TZ` (опционально), `DAILY_REPORT_TOP_IPS`
|
||||
- `DAILY_REPORT_HOUR` (0..23), `DAILY_REPORT_TZ` (опционально), `NOTIFY_TZ` (опционально), `SSH_ACCEPT_NOTIFY_DEDUP_SEC`, `DAILY_REPORT_TOP_IPS`
|
||||
- `BRUTE_WINDOW_SEC`, `BRUTE_MIN_FAILS`, `BRUTE_NOTIFY_COOLDOWN_SEC`
|
||||
- `PROMETHEUS_TEXTFILE_DIR` — каталог для `ssh_monitor.prom` (совместимость с node_exporter textfile collector)
|
||||
- `HEALTHCHECK_STATUS_FILE` — путь к JSON-файлу с меткой последней итерации цикла
|
||||
@@ -59,6 +59,8 @@ Bash-скрипт мониторинга **SSH**, **SUDO** и событий **`
|
||||
- `LOGIND_SKIP_REMOTE` — `1` (по умолчанию): для новой сессии logind, если доступен `loginctl`, не отправляется второе Telegram, если сессия уже учтена в **`monitor_ssh`**: при **`Type=ssh`** или если **`Service`** указывает на **sshd** (часто **`Type=tty` + `Service=sshd`**); при пустом ответе `loginctl` делаются короткие повторы. Поставьте `0`, если нужны отдельные алерты logind и для SSH-сессий.
|
||||
- `DAILY_REPORT_HOUR` — час (0..23), после наступления которого в **текущих календарных сутках** (в выбранной ниже зоне) отправляется не более одного ежедневного отчёта.
|
||||
- `DAILY_REPORT_TZ` — необязательная **IANA**-зона (`Europe/Moscow`, `Asia/Yekaterinburg`, …). Если **пусто**, для отчёта используется та же зона, что и у команды `date` у процесса монитора (как правило, совпадает с `timedatectl` / `/etc/localtime` на сервере). Если сервис запускается с `TZ=UTC` в unit-файле, без `DAILY_REPORT_TZ` отчёт ориентируется на **UTC** — тогда задайте явную зону в конфиге.
|
||||
- `NOTIFY_TZ` — **IANA**-зона для строк **«🕐 Время»** в Telegram/Zabbix/email (и аналогичных текстах). **Пусто** — используется **`DAILY_REPORT_TZ`**, если она задана, иначе зона процесса. Частая причина «время в теле сообщения UTC, а в заголовке чата локальное»: в **`ssh-monitor.service`** задано **`Environment=TZ=UTC`** — тогда задайте **`NOTIFY_TZ`** (или **`DAILY_REPORT_TZ`**) на вашу локаль, например `Asia/Vladivostok`.
|
||||
- `SSH_ACCEPT_NOTIFY_DEDUP_SEC` — не чаще одного Telegram по **успешному SSH (`Accepted`)** на одну пару **пользователь + IP** за указанное число **секунд** (по умолчанию **5**). Снимает дубли, когда в journal две строки с **разными портами клиента** за один вход. **`0`** — отключить этот антидубль (останется только дедупликация внутри одного прохода `monitor_ssh` по `user|ip|port`).
|
||||
- `DAILY_REPORT_TOP_IPS` — сколько IP показывать в топе неудачных попыток за 24 часа.
|
||||
- `BRUTE_WINDOW_SEC` — окно (секунды) для оценки «массового» брутфорса по `journalctl`.
|
||||
- `BRUTE_MIN_FAILS` — минимум неудачных попыток за окно для тревоги.
|
||||
@@ -105,7 +107,7 @@ Bash-скрипт мониторинга **SSH**, **SUDO** и событий **`
|
||||
- Без **`journalctl`** на хосте этот блок **не работает** (как и часть других функций, завязанных на journal).
|
||||
- Для разбора «новой сессии» используются типичные англоязычные форматы (`New session … of user …`). При несовпадении формата строка всё равно попадёт в лог с пометкой о неудачном разборе.
|
||||
- **`loginctl`** нужен для **`LOGIND_SKIP_REMOTE`**: по `Type` и **`Service`** решается, не дублировать ли Telegram с **`monitor_ssh`** (см. описание `LOGIND_SKIP_REMOTE` выше).
|
||||
- **`monitor_ssh`**: события **sshd** читаются из journal преимущественно как **`journalctl _COMM=sshd`** (запасные варианты — юниты `sshd` / `ssh`), строки **`sort -u`**, а для **`Accepted`** в одном проходе цикла подавляется повтор с тем же **пользователем, IP и номером порта клиента** — чтобы не было двух одинаковых «успешных SSH» из дублирующихся записей журнала.
|
||||
- **`monitor_ssh`**: события **sshd** читаются из journal преимущественно как **`journalctl _COMM=sshd`** (запасные варианты — юниты `sshd` / `ssh`), строки **`sort -u`**, для **`Accepted`** в одном проходе — дедуп по **пользователь|IP|порт**; между проходами цикла — пауза **`SSH_ACCEPT_NOTIFY_DEDUP_SEC`** для той же пары **пользователь|IP** (см. переменную в конфиге).
|
||||
|
||||
Команда **`ssh-monitor --check-config`** выводит актуальные значения, в том числе параметры logind.
|
||||
|
||||
|
||||
+54
-15
@@ -7,7 +7,7 @@ IFS=$'\n\t'
|
||||
# ============================================
|
||||
|
||||
CONFIG_FILE="/etc/ssh-monitor.conf"
|
||||
SSH_MONITOR_VERSION="0.9.5.1"
|
||||
SSH_MONITOR_VERSION="0.9.5.2"
|
||||
|
||||
TELEGRAM_BOT_TOKEN=""
|
||||
TELEGRAM_CHAT_ID=""
|
||||
@@ -42,6 +42,10 @@ DAILY_REPORT_TOP_IPS=5
|
||||
# Пусто = календарь и час отчёта в зоне процесса (как `date`, обычно совпадает с /etc/localtime).
|
||||
# Иначе IANA, например Europe/Moscow — явная зона для DAILY_REPORT_HOUR и даты «сегодня» в отчёте.
|
||||
DAILY_REPORT_TZ=""
|
||||
# IANA-зона для строк «🕐 Время» в Telegram/Zabbix/email. Пусто = тогда DAILY_REPORT_TZ, если она задана, иначе зона процесса (часто UTC у systemd — см. README).
|
||||
NOTIFY_TZ=""
|
||||
# Не слать повтор «Accepted» для той же пары user+IP чаще, чем раз в N секунд (разные port в журнале — один вход).
|
||||
SSH_ACCEPT_NOTIFY_DEDUP_SEC=5
|
||||
|
||||
# Временные файлы для отслеживания уже обработанных событий
|
||||
LAST_SSH_CHECK_FILE="/var/log/last_ssh_check"
|
||||
@@ -85,6 +89,7 @@ WHITELIST_SUBNETS=(
|
||||
|
||||
declare -A FAIL_COUNTS
|
||||
declare -A BRUTE_LAST_NOTIFY
|
||||
declare -A SSH_ACCEPT_LAST_NOTIFY
|
||||
|
||||
CHECK_CONFIG_ONLY=0
|
||||
DRY_RUN=0
|
||||
@@ -158,6 +163,8 @@ load_config() {
|
||||
local cfg_daily_report_hour="${DAILY_REPORT_HOUR}"
|
||||
local cfg_daily_report_top_ips="${DAILY_REPORT_TOP_IPS}"
|
||||
local cfg_daily_report_tz="${DAILY_REPORT_TZ}"
|
||||
local cfg_notify_tz="${NOTIFY_TZ:-}"
|
||||
local cfg_ssh_accept_notify_dedup_sec="${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}"
|
||||
local cfg_last_ssh_check_file="${LAST_SSH_CHECK_FILE}"
|
||||
local cfg_last_sudo_check_file="${LAST_SUDO_CHECK_FILE}"
|
||||
local cfg_last_security_events_file="${LAST_SECURITY_EVENTS_FILE}"
|
||||
@@ -222,6 +229,11 @@ load_config() {
|
||||
DAILY_REPORT_HOUR="${DAILY_REPORT_HOUR:-$cfg_daily_report_hour}"
|
||||
DAILY_REPORT_TOP_IPS="${DAILY_REPORT_TOP_IPS:-$cfg_daily_report_top_ips}"
|
||||
DAILY_REPORT_TZ="$(trim_value "${DAILY_REPORT_TZ:-$cfg_daily_report_tz}")"
|
||||
NOTIFY_TZ="$(trim_value "${NOTIFY_TZ:-$cfg_notify_tz}")"
|
||||
SSH_ACCEPT_NOTIFY_DEDUP_SEC="$(trim_value "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-$cfg_ssh_accept_notify_dedup_sec}")"
|
||||
if ! [[ "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}" =~ ^[0-9]+$ ]]; then
|
||||
SSH_ACCEPT_NOTIFY_DEDUP_SEC=5
|
||||
fi
|
||||
BRUTE_WINDOW_SEC="${BRUTE_WINDOW_SEC:-$cfg_brute_window_sec}"
|
||||
BRUTE_MIN_FAILS="${BRUTE_MIN_FAILS:-$cfg_brute_min_fails}"
|
||||
BRUTE_NOTIFY_COOLDOWN_SEC="${BRUTE_NOTIFY_COOLDOWN_SEC:-$cfg_brute_notify_cooldown_sec}"
|
||||
@@ -255,6 +267,17 @@ report_date() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Время в текстах уведомлений (Telegram и др.): явная зона, иначе как у ежедневного отчёта, иначе как у процесса.
|
||||
notification_date() {
|
||||
if [ -n "${NOTIFY_TZ:-}" ]; then
|
||||
TZ="$NOTIFY_TZ" date "$@"
|
||||
elif [ -n "${DAILY_REPORT_TZ:-}" ]; then
|
||||
TZ="$DAILY_REPORT_TZ" date "$@"
|
||||
else
|
||||
date "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
is_telegram_configured() {
|
||||
[ -n "${TELEGRAM_BOT_TOKEN:-}" ] && [ -n "${TELEGRAM_CHAT_ID:-}" ]
|
||||
}
|
||||
@@ -802,7 +825,7 @@ block_ip() {
|
||||
message="${message}🌐 IP: ${ip}"$'\n'
|
||||
message="${message}📊 Неудачных попыток: ${attempts}"$'\n'
|
||||
message="${message}⏱️ Блокировка на: ${ban_time_hours} час(ов)"$'\n'
|
||||
message="${message}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
message="${message}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$message"
|
||||
write_log "AUTO-BAN: IP $ip заблокирован на $ban_time_hours часов ($attempts попыток)"
|
||||
}
|
||||
@@ -827,7 +850,7 @@ unblock_expired_ips() {
|
||||
|
||||
local message=" 🔓 IP РАЗБЛОКИРОВАН "$'\n'
|
||||
message="${message}🌐 IP: ${ip}"$'\n'
|
||||
message="${message}🕐 Время разблокировки: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
message="${message}🕐 Время разблокировки: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$message"
|
||||
|
||||
unblocked=$((unblocked + 1))
|
||||
@@ -980,17 +1003,31 @@ monitor_ssh() {
|
||||
write_log "SSH Accepted: дубль в журнале (user=${user} ip=${ip:-} port=${dedupe_port:-?}), второе уведомление не отправляем"
|
||||
continue
|
||||
fi
|
||||
local dedupe_net_key last_nf now_ded delta
|
||||
dedupe_net_key="${user}|${ip:-}"
|
||||
if [[ "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}" =~ ^[0-9]+$ ]] && [ "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}" -gt 0 ]; then
|
||||
now_ded=$(date '+%s')
|
||||
last_nf="${SSH_ACCEPT_LAST_NOTIFY[$dedupe_net_key]:-0}"
|
||||
if [ "${last_nf:-0}" -gt 0 ]; then
|
||||
delta=$((now_ded - last_nf))
|
||||
if [ "$delta" -ge 0 ] && [ "$delta" -lt "$SSH_ACCEPT_NOTIFY_DEDUP_SEC" ]; then
|
||||
write_log "SSH Accepted: повтор для user=${user} ip=${ip:-} через ${delta}s (< ${SSH_ACCEPT_NOTIFY_DEDUP_SEC}s), второе Telegram не отправляем"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
SSH_ACCEPT_NOTIFY_KEYS[$dedupe_key]=1
|
||||
SSH_ACCEPT_LAST_NOTIFY[$dedupe_net_key]=$(date '+%s')
|
||||
local message=" ✅ УСПЕШНОЕ SSH ПОДКЛЮЧЕНИЕ "$'\n'
|
||||
message="${message}👤 Пользователь: ${user}"$'\n'
|
||||
message="${message}🌐 IP адрес: ${ip:-local}"$'\n'
|
||||
message="${message}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
message="${message}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$message"
|
||||
write_log "SSH успешный вход: $user с IP ${ip:-local}"
|
||||
if [ "$user" = "root" ]; then
|
||||
local rmsg=" 🔑 SSH ВХОД ПОД ROOT "$'\n'
|
||||
rmsg="${rmsg}🌐 IP: ${ip:-local}"$'\n'
|
||||
rmsg="${rmsg}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
rmsg="${rmsg}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$rmsg"
|
||||
fi
|
||||
fi
|
||||
@@ -1019,7 +1056,7 @@ monitor_ssh() {
|
||||
message="${message}👤 Пользователь: ${user}"$'\n'
|
||||
message="${message}🌐 IP адрес: ${ip}"$'\n'
|
||||
message="${message}📊 Попытка ${current_attempts} из ${MAX_ATTEMPTS}"$'\n'
|
||||
message="${message}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
message="${message}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$message"
|
||||
fi
|
||||
write_log "SSH неудачная попытка: $user с IP $ip (попытка $current_attempts из $MAX_ATTEMPTS)"
|
||||
@@ -1134,7 +1171,7 @@ monitor_sudo() {
|
||||
fi
|
||||
message="${message}💻 Команда: ${sudo_cmd}"$'\n'
|
||||
message="${message}📁 Директория: ${pwd:-unknown}"$'\n'
|
||||
message="${message}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
message="${message}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$message"
|
||||
write_log "SUDO: $user выполнил $sudo_cmd${run_as:+ (USER=$run_as)}"
|
||||
fi
|
||||
@@ -1175,7 +1212,7 @@ monitor_security_events() {
|
||||
hk="$(echo "$chunk" | grep -Ei "REMOTE HOST IDENTIFICATION HAS CHANGED" | head -n 3)"
|
||||
local m=" 🔐 ВНИМАНИЕ: изменение SSH host key / MITM? "$'\n'
|
||||
m="${m}$(printf '%s\n' "$hk")"
|
||||
m="${m}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
m="${m}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$m"
|
||||
write_log "SECURITY: обнаружено сообщение об изменении host key"
|
||||
fi
|
||||
@@ -1196,7 +1233,7 @@ monitor_security_events() {
|
||||
local bm=" 🧨 ВОЗМОЖНЫЙ МАССОВЫЙ БРУТФОРС SSH "$'\n'
|
||||
bm="${bm}🌐 IP: ${ip}"$'\n'
|
||||
bm="${bm}📊 Неудачных попыток за ~${BRUTE_WINDOW_SEC}s: ${count}"$'\n'
|
||||
bm="${bm}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
bm="${bm}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$bm"
|
||||
write_log "SECURITY: массовый брутфорс? IP=$ip fails=${count} за окно ${BRUTE_WINDOW_SEC}s"
|
||||
fi
|
||||
@@ -1307,7 +1344,7 @@ monitor_logind() {
|
||||
local msg=" 🖥️ НОВАЯ СЕССИЯ (systemd-logind) "$'\n'
|
||||
msg="${msg}👤 Пользователь: ${user:-неизвестно}"$'\n'
|
||||
msg="${msg}🆔 Сессия: ${sid:-?}"$'\n'
|
||||
msg="${msg}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
msg="${msg}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$msg"
|
||||
write_log "LOGIND: новая сессия: ${line}"
|
||||
else
|
||||
@@ -1324,7 +1361,7 @@ monitor_logind() {
|
||||
fi
|
||||
local msg_r=" 🚪 СЕССИЯ ЗАКРЫТА (systemd-logind) "$'\n'
|
||||
msg_r="${msg_r}🆔 Сессия: ${sess_r:-?}"$'\n'
|
||||
msg_r="${msg_r}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
msg_r="${msg_r}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$msg_r"
|
||||
fi
|
||||
|
||||
@@ -1332,7 +1369,7 @@ monitor_logind() {
|
||||
if [ "${LOGIND_NOTIFY_FAILED:-1}" = "1" ]; then
|
||||
local msg_f=" ❌ СБОЙ (systemd-logind) "$'\n'
|
||||
msg_f="${msg_f}📝 ${line}"$'\n'
|
||||
msg_f="${msg_f}🕐 Время: $(date '+%d.%m.%Y %H:%M:%S')"
|
||||
msg_f="${msg_f}🕐 Время: $(notification_date '+%d.%m.%Y %H:%M:%S')"
|
||||
notify_send "$msg_f"
|
||||
write_log "LOGIND: сбой: $line"
|
||||
fi
|
||||
@@ -1515,7 +1552,7 @@ send_heartbeat() {
|
||||
local timestamp
|
||||
timestamp=$(date '+%s')
|
||||
local timestamp_human
|
||||
timestamp_human=$(date '+%d.%m.%Y %H:%M:%S')
|
||||
timestamp_human=$(notification_date '+%d.%m.%Y %H:%M:%S')
|
||||
|
||||
local message=" ❤️ Heartbeat - скрипт мониторинга работает "$'\n'
|
||||
message="${message}🖥️ Сервер: $(server_display_name_with_ip)"$'\n'
|
||||
@@ -1572,7 +1609,7 @@ write_health_and_metrics() {
|
||||
|
||||
send_startup_notification() {
|
||||
local timestamp
|
||||
timestamp=$(date '+%d.%m.%Y %H:%M:%S')
|
||||
timestamp=$(notification_date '+%d.%m.%Y %H:%M:%S')
|
||||
local whitelist_count=$((${#WHITELIST_IPS[@]} + ${#WHITELIST_SUBNETS[@]}))
|
||||
|
||||
local message=" ✅ СКРИПТ МОНИТОРИНГА ЗАПУЩЕН "$'\n'
|
||||
@@ -1594,7 +1631,7 @@ send_shutdown_notification() {
|
||||
SHUTDOWN_NOTIFIED=1
|
||||
|
||||
local timestamp
|
||||
timestamp=$(date '+%d.%m.%Y %H:%M:%S')
|
||||
timestamp=$(notification_date '+%d.%m.%Y %H:%M:%S')
|
||||
local message=" ⚠️ СКРИПТ МОНИТОРИНГА ОСТАНОВЛЕН "$'\n'
|
||||
message="${message}🖥️ Сервер: $(server_display_name_with_ip)"$'\n'
|
||||
message="${message}🕐 Время остановки: ${timestamp}"
|
||||
@@ -1648,6 +1685,8 @@ run_check_config() {
|
||||
printf 'LOG_FILE=%s\n' "$LOG_FILE"
|
||||
printf 'DAILY_REPORT_HOUR=%s\n' "$DAILY_REPORT_HOUR"
|
||||
printf 'DAILY_REPORT_TZ=%s (пусто = зона процесса/date)\n' "${DAILY_REPORT_TZ:-}"
|
||||
printf 'NOTIFY_TZ=%s (пусто = DAILY_REPORT_TZ или зона процесса; см. README)\n' "${NOTIFY_TZ:-}"
|
||||
printf 'SSH_ACCEPT_NOTIFY_DEDUP_SEC=%s\n' "${SSH_ACCEPT_NOTIFY_DEDUP_SEC:-5}"
|
||||
printf 'DAILY_REPORT_TOP_IPS=%s\n' "$DAILY_REPORT_TOP_IPS"
|
||||
printf 'BRUTE_WINDOW_SEC=%s BRUTE_MIN_FAILS=%s\n' "$BRUTE_WINDOW_SEC" "$BRUTE_MIN_FAILS"
|
||||
printf 'PROMETHEUS_TEXTFILE_DIR=%s\n' "${PROMETHEUS_TEXTFILE_DIR:-}"
|
||||
|
||||
@@ -61,6 +61,10 @@ DAILY_REPORT_HOUR="9"
|
||||
# IANA-зона для «9:00» и календарной даты отчёта; пусто = как у команды date (обычно локаль сервера, см. timedatectl)
|
||||
DAILY_REPORT_TZ=""
|
||||
DAILY_REPORT_TOP_IPS="5"
|
||||
# IANA-зона для «🕐 Время» в Telegram/Zabbix/email. Пусто = как DAILY_REPORT_TZ, иначе зона процесса (часто UTC в systemd — см. README).
|
||||
NOTIFY_TZ=""
|
||||
# Не чаще 1 успешного SSH (Accepted) в Telegram на пару user+IP за N секунд (разные port в журнале). 0 = только дедуп внутри одного прохода.
|
||||
SSH_ACCEPT_NOTIFY_DEDUP_SEC="5"
|
||||
|
||||
BAN_TIME="3600"
|
||||
MAX_ATTEMPTS="3"
|
||||
|
||||
Reference in New Issue
Block a user