diff --git a/plugins/fail2ban/README.md b/plugins/fail2ban/README.md new file mode 100644 index 000000000..6676a39b1 --- /dev/null +++ b/plugins/fail2ban/README.md @@ -0,0 +1,37 @@ +# fail2ban-client + +## Description + +Zsh completion for the `fail2ban-client` command. +This plugin provides: + +- Completion for subcommands (`start`, `restart`, `reload`, `stop`, `unban`, `status`, `set`, `get`, `add`, etc.) +- Dynamic completion of active jails +- Contextual completion of options for `set` and `get` (e.g., `bantime`, `maxretry`, `ignoreip`, etc.) +- Automatic handling of `sudo` if required + +## Installation + +To use it, add **fail2ban** to the plugins array in your zshrc file: + +```bash +plugins=(... fail2ban) +``` + +## Usage + +Type `fail2ban-client ` to trigger completion. +Examples: + +```bash +fail2ban-client set # suggests jails +fail2ban-client set sshd # suggests possible actions +fail2ban-client get sshd # suggests available properties +fail2ban-client status # suggests jails or the 'extended' option +``` + +## Compatibility + +- Zsh version 5.x or higher +- Works with or without root access (uses `sudo` if needed) +- Designed to be used as a plugin in Oh My Zsh diff --git a/plugins/fail2ban/fail2ban.plugin.zsh b/plugins/fail2ban/fail2ban.plugin.zsh new file mode 100644 index 000000000..8bd4db472 --- /dev/null +++ b/plugins/fail2ban/fail2ban.plugin.zsh @@ -0,0 +1,117 @@ +#compdef fail2ban-client + +_fail2ban_jails() { + # Récupère la liste des jails actifs + if [[ $EUID -eq 0 ]]; then + fail2ban-client status 2>/dev/null | awk '/Jail list/ { sub(/^.*:[ \t]*/, ""); gsub(/[ \t]+/, ""); split($0, a, /,/); for (i in a) if (a[i]) print a[i] }' + else + sudo fail2ban-client status 2>/dev/null | awk '/Jail list/ { sub(/^.*:[ \t]*/, ""); gsub(/[ \t]+/, ""); split($0, a, /,/); for (i in a) if (a[i]) print a[i] }' + fi +} + +_fail2ban-client() { + local curcontext="$curcontext" state line cmdpos + typeset -A opt_args + + cmdpos=${words[(i)fail2ban-client]} + + _arguments \ + '1:cmd:(start restart reload stop unban banned status ping set get add echo help version)' \ + '*::arg:->args' + + if [[ "$state" = args ]]; then + local -a jails + + case $line[1] in + set) + if (( CURRENT - cmdpos == 1 )); then + jails=($(_fail2ban_jails)) + _describe 'jail' jails + elif (( CURRENT - cmdpos == 2 )); then + _values 'action' \ + 'idle' 'ignoreself' 'addignoreip' 'delignoreip' 'ignorecommand' 'ignorecache' \ + 'addlogpath' 'dellogpath' 'logencoding' 'addjournalmatch' 'deljournalmatch' \ + 'addfailregex' 'delfailregex' 'addignoreregex' 'delignoreregex' 'findtime' \ + 'bantime' 'datepattern' 'usedns' 'attempt' 'banip' 'unbanip' 'maxretry' \ + 'maxmatches' 'maxlines' 'addaction' 'delaction' 'action' + elif (( CURRENT - cmdpos > 2 )); then + case $line[3] in + idle) _values 'option' 'on' 'off' ;; + ignoreself) _values 'option' 'true' 'false' ;; + addlogpath) (( CURRENT - cmdpos == 4 )) && _values 'option' 'tail' ;; + unbanip) (( CURRENT - cmdpos == 3 )) && _values 'option' '--report-absent' ;; + action) + if (( CURRENT - cmdpos == 3 )); then + _message "nom de l'action (ACT)" + elif (( CURRENT - cmdpos == 4 )); then + _values 'action property' \ + 'actionstart' 'actionstop' 'actioncheck' 'actionban' 'actionunban' 'timeout' + fi + ;; + esac + fi + ;; + + get) + if (( CURRENT - cmdpos == 1 )); then + jails=($(_fail2ban_jails)) + _describe 'jail' jails + elif (( CURRENT - cmdpos == 2 )); then + _values 'property' \ + 'banned' 'logpath' 'logencoding' 'journalmatch' 'ignoreself' 'ignoreip' \ + 'ignorecommand' 'failregex' 'ignoreregex' 'findtime' 'bantime' 'datepattern' \ + 'usedns' 'banip' 'maxretry' 'maxmatches' 'maxlines' 'actions' 'action' \ + 'actionproperties' 'actionmethods' + elif (( CURRENT - cmdpos > 2 )); then + case $line[3] in + action) + if (( CURRENT - cmdpos == 3 )); then + _message "nom de l'action (ACT)" + elif (( CURRENT - cmdpos == 4 )); then + _values 'action property' \ + 'actionstart' 'actionstop' 'actioncheck' 'actionban' 'actionunban' 'timeout' + fi + ;; + actionproperties|actionmethods) + (( CURRENT - cmdpos == 3 )) && _message "nom de l'action (ACT)" + ;; + banip) + (( CURRENT - cmdpos == 3 )) && _values 'option' '--with-time' + ;; + esac + fi + ;; + + status|restart|start|stop) + if (( CURRENT - cmdpos == 1 )); then + jails=($(_fail2ban_jails)) + _describe 'jail' jails + elif (( CURRENT - cmdpos == 2 )) && [[ $line[1] == "status" ]]; then + _values 'flavor' 'extended' + fi + ;; + + reload) + if (( CURRENT - cmdpos == 1 )); then + jails=($(_fail2ban_jails)) + _values 'option' '--all' + _describe 'jail' jails + fi + ;; + + unban) + (( CURRENT - cmdpos == 1 )) && _values 'option' '--all' + ;; + + add) + if (( CURRENT - cmdpos == 1 )); then + _message 'nom du jail à ajouter' + elif (( CURRENT - cmdpos == 2 )); then + _values 'backend' 'auto' 'pyinotify' 'systemd' 'gamin' 'polling' + fi + ;; + esac + fi +} + +compdef _fail2ban-client fail2ban-client