feature: bash completes the vpn-* commands, their options and the names they take.
Release / release (push) Successful in 12s
Release / release (push) Successful in 12s
This commit is contained in:
1 parent
8cac21845a
commit
81b7f4cac6
12 files changed
+459
No files matched your search
@@ -1043,3 +1043,25 @@ HTTPS, a public name and the web service. Clients are managed like service accou
|
|||||||
it renames it in the clients. The signing key does not rotate; replacing it invalidates every ID
|
it renames it in the clients. The signing key does not rotate; replacing it invalidates every ID
|
||||||
token issued. Wrong client secrets lock the client like any account. The implicit and hybrid
|
token issued. Wrong client secrets lock the client like any account. The implicit and hybrid
|
||||||
flows, dynamic client registration and public clients without a secret are not offered.
|
flows, dynamic client registration and public clients without a secret are not offered.
|
||||||
|
|
||||||
|
## ADR-38: Bash completions are files per command in bash-completion's completions directory
|
||||||
|
|
||||||
|
Status: Accepted
|
||||||
|
|
||||||
|
Context: The `vpn-*` commands have many subcommands, options and names (users, groups, issuing
|
||||||
|
CAs, templates, settings) that are hard to remember. bash-completion's README recommends its
|
||||||
|
`completionsdir`, `/usr/share/bash-completion/completions` on Ubuntu, whose files it loads on the
|
||||||
|
first Tab of their command, and calls the eagerly loaded `/etc/bash_completion.d` not
|
||||||
|
recommended; it prefers the name `<command>.bash`, which noble's 2.11 and resolute's 2.16 both
|
||||||
|
look up.
|
||||||
|
|
||||||
|
Decision: The package installs `<command>.bash` for each `vpn-*` command into
|
||||||
|
`/usr/share/bash-completion/completions` and recommends `bash-completion`. The completions read
|
||||||
|
the names they offer from the commands themselves (`--json list`) or the package's Python
|
||||||
|
modules (the schema, the configuration, the PKI's templates and reasons), not from copies, and
|
||||||
|
send errors to `/dev/null`, so a user who may not read them gets the fixed words only.
|
||||||
|
|
||||||
|
Consequences: Completions follow the code without being edited for each new setting or name. A
|
||||||
|
Tab that offers names runs a command or Python, which takes a fraction of a second. The files
|
||||||
|
are not conffiles; an administrator overrides one in `/etc/bash_completion.d` or the user's own
|
||||||
|
completions directory.
|
||||||
@@ -355,6 +355,23 @@ indented, with mode 0600, and reminds that `vpn-router-setup` applies it. The st
|
|||||||
writes the file the same way, and a lock keeps the two from overwriting each other's change. A
|
writes the file the same way, and a lock keeps the two from overwriting each other's change. A
|
||||||
refused request exits with status 2, any other failure with 1.
|
refused request exits with status 2, any other failure with 1.
|
||||||
|
|
||||||
|
## Bash completion
|
||||||
|
|
||||||
|
Bash completes the commands, options and arguments of `vpn-router-user`, `vpn-router-group`,
|
||||||
|
`vpn-router-token`, `vpn-config-edit`, `vpn-router-backup`, `vpn-router-ca` and
|
||||||
|
`vpn-router-caddy` with the Tab key. The package installs a file per command in
|
||||||
|
`/usr/share/bash-completion/completions`, which the `bash-completion` package, recommended by
|
||||||
|
`vpn-router`, loads on the first Tab after the command. For root, who can read them, the
|
||||||
|
completions also offer the users and groups of the directory, the settings and site-to-site
|
||||||
|
connections of `vpn-router.json` with `true` and `false` for a boolean setting, and the issuing CAs and
|
||||||
|
certificate templates; for other users only the fixed words.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo -i
|
||||||
|
vpn-config-edit set oidc.<Tab>
|
||||||
|
vpn-router-user passwd <Tab>
|
||||||
|
```
|
||||||
|
|
||||||
## Applying changes
|
## Applying changes
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|||||||
@@ -1,3 +1,16 @@
|
|||||||
|
vpn-router (0.28.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
|
feature: bash completes the vpn-* commands, their options and the names they take.
|
||||||
|
|
||||||
|
* Bash completes the commands, options and arguments of vpn-router-user,
|
||||||
|
vpn-router-group, vpn-router-token, vpn-config-edit, vpn-router-backup,
|
||||||
|
vpn-router-ca and vpn-router-caddy, from
|
||||||
|
/usr/share/bash-completion/completions; for root also the users,
|
||||||
|
groups, issuing CAs, templates, settings and site-to-site connections.
|
||||||
|
* The package recommends bash-completion.
|
||||||
|
|
||||||
|
-- Slawomir Koszewski <slawek@koszewscy.waw.pl> Mon, 26 Oct 2026 16:00:00 +0100
|
||||||
|
|
||||||
vpn-router (0.27.0-1) unstable; urgency=medium
|
vpn-router (0.27.0-1) unstable; urgency=medium
|
||||||
|
|
||||||
feature: the web service is an OpenID Provider, which signs the directory's users in to other systems, the clients being service accounts with redirect URIs.
|
feature: the web service is an OpenID Provider, which signs the directory's users in to other systems, the clients being service accounts with redirect URIs.
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ Depends: ${misc:Depends},
|
|||||||
iproute2,
|
iproute2,
|
||||||
systemd-resolved,
|
systemd-resolved,
|
||||||
zstd
|
zstd
|
||||||
|
Recommends: bash-completion
|
||||||
Suggests: caddy,
|
Suggests: caddy,
|
||||||
rclone,
|
rclone,
|
||||||
proxmox-backup-client-static
|
proxmox-backup-client-static
|
||||||
|
|||||||
@@ -31,5 +31,6 @@ src/usr/lib/vpn-router/generate-config usr/lib/vpn-router/
|
|||||||
src/usr/lib/vpn-router/vpnrouter_platforms/*.py usr/lib/vpn-router/vpnrouter_platforms/
|
src/usr/lib/vpn-router/vpnrouter_platforms/*.py usr/lib/vpn-router/vpnrouter_platforms/
|
||||||
src/usr/share/vpn-router/templates/* usr/share/vpn-router/templates/
|
src/usr/share/vpn-router/templates/* usr/share/vpn-router/templates/
|
||||||
src/usr/share/vpn-router/sql/* usr/share/vpn-router/sql/
|
src/usr/share/vpn-router/sql/* usr/share/vpn-router/sql/
|
||||||
|
src/usr/share/bash-completion/completions/*.bash usr/share/bash-completion/completions/
|
||||||
src/usr/lib/systemd/system/caddy.service.d/vpn-router.conf usr/lib/systemd/system/caddy.service.d/
|
src/usr/lib/systemd/system/caddy.service.d/vpn-router.conf usr/lib/systemd/system/caddy.service.d/
|
||||||
src/usr/share/doc/vpn-router/vpn-router.json.example usr/share/doc/vpn-router/
|
src/usr/share/doc/vpn-router/vpn-router.json.example usr/share/doc/vpn-router/
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# bash completion for vpn-config-edit -*- shell-script -*-
|
||||||
|
|
||||||
|
# Python of the package that answers from its schema (vpnrouter.SCHEMA, vpnrouter.CONNECTION) and, read as root, the
|
||||||
|
# site-to-site connections of the configuration: settings prints SECTION.OPTION of every setting and
|
||||||
|
# site_to_site.NAME.OPTION of every connection, connections site_to_site.NAME, and values the values of a boolean
|
||||||
|
# setting, $1.
|
||||||
|
_vpn_config_edit_python()
|
||||||
|
{
|
||||||
|
python3 -c '
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, "/usr/lib/vpn-router")
|
||||||
|
import vpnrouter
|
||||||
|
try:
|
||||||
|
connections = vpnrouter.read_settings().get("site_to_site", {})
|
||||||
|
except (OSError, vpnrouter.ConfigError):
|
||||||
|
connections = {}
|
||||||
|
if sys.argv[1] == "settings":
|
||||||
|
print("\n".join(f"{section}.{option}" for section, options in vpnrouter.SCHEMA.items() for option in options))
|
||||||
|
print("\n".join(f"site_to_site.{name}.{option}" for name in connections for option in vpnrouter.CONNECTION))
|
||||||
|
elif sys.argv[1] == "connections":
|
||||||
|
print("\n".join(f"site_to_site.{name}" for name in connections))
|
||||||
|
else:
|
||||||
|
section, _, option = sys.argv[2].rpartition(".")
|
||||||
|
defaults = vpnrouter.CONNECTION if section.startswith("site_to_site.") else vpnrouter.SCHEMA.get(section, {})
|
||||||
|
if isinstance(defaults.get(option), bool):
|
||||||
|
print("true\nfalse")
|
||||||
|
' "$@" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_vpn_config_edit()
|
||||||
|
{
|
||||||
|
local cur prev words cword split
|
||||||
|
_init_completion -s || return
|
||||||
|
|
||||||
|
# The command is the first word that is not an option; the arguments are the words after it.
|
||||||
|
local i command='' args=()
|
||||||
|
for ((i = 1; i < cword; i++)); do
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
[[ ${words[i]} != -* ]] && command=${words[i]}
|
||||||
|
elif [[ ${words[i]} != -* ]]; then
|
||||||
|
args+=("${words[i]}")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W '--help' -- "$cur"))
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $command,${#args[@]} in
|
||||||
|
,*) COMPREPLY=($(compgen -W 'show set remove' -- "$cur")) ;;
|
||||||
|
set,0) COMPREPLY=($(compgen -W "$(_vpn_config_edit_python settings)" -- "$cur")) ;;
|
||||||
|
set,1) COMPREPLY=($(compgen -W "$(_vpn_config_edit_python values "${args[0]}")" -- "$cur")) ;;
|
||||||
|
remove,0) COMPREPLY=($(compgen -W "$(_vpn_config_edit_python connections)" -- "$cur")) ;;
|
||||||
|
esac
|
||||||
|
} &&
|
||||||
|
complete -F _vpn_config_edit vpn-config-edit
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# bash completion for vpn-router-backup -*- shell-script -*-
|
||||||
|
|
||||||
|
_vpn_router_backup()
|
||||||
|
{
|
||||||
|
local cur prev words cword split
|
||||||
|
_init_completion -s || return
|
||||||
|
|
||||||
|
# The command is the first word that is not an option; the arguments are the words after it.
|
||||||
|
local i command='' args=0 pbs=false
|
||||||
|
for ((i = 1; i < cword; i++)); do
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
[[ ${words[i]} != -* ]] && command=${words[i]}
|
||||||
|
elif [[ ${words[i]} == --pbs ]]; then
|
||||||
|
pbs=true
|
||||||
|
elif [[ ${words[i]} != -* ]]; then
|
||||||
|
((args++))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W '--help' -- "$cur"))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W 'run list restore' -- "$cur"))
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W "--help$([[ $command == restore ]] && echo ' --pbs --yes')" -- "$cur"))
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# restore takes a local archive, or with --pbs a snapshot name, which vpn-router-backup list shows.
|
||||||
|
if [[ $command == restore ]] && ((args == 0)) && ! $pbs; then
|
||||||
|
_filedir
|
||||||
|
fi
|
||||||
|
} &&
|
||||||
|
complete -F _vpn_router_backup vpn-router-backup
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
# bash completion for vpn-router-ca -*- shell-script -*-
|
||||||
|
|
||||||
|
# Python of the package that prints the revocation reasons (reasons) or, from the configuration read as root, the
|
||||||
|
# issuing CAs (cas) or the certificate templates (templates), which other users do not get.
|
||||||
|
_vpn_router_ca_python()
|
||||||
|
{
|
||||||
|
python3 -c '
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, "/usr/lib/vpn-router")
|
||||||
|
import vpnrouter
|
||||||
|
import vpnrouter_pki
|
||||||
|
if sys.argv[1] == "reasons":
|
||||||
|
print("\n".join(vpnrouter_pki.REASONS))
|
||||||
|
else:
|
||||||
|
cfg = vpnrouter.load_config()
|
||||||
|
print("\n".join(vpnrouter.issuing_cas(cfg) if sys.argv[1] == "cas" else vpnrouter.pki_templates(cfg)))
|
||||||
|
' "$@" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_vpn_router_ca()
|
||||||
|
{
|
||||||
|
local cur prev words cword split
|
||||||
|
_init_completion -s || return
|
||||||
|
|
||||||
|
# The command and, for ca and root, the action are the first words that are not options; the arguments are the
|
||||||
|
# words after them but option values.
|
||||||
|
local i command='' action='' args=0
|
||||||
|
for ((i = 1; i < cword; i++)); do
|
||||||
|
case ${words[i]} in
|
||||||
|
--ca | --template | --csr | --subject | --san | --pfx | --reason | --out) ((i++)) ;;
|
||||||
|
-*) ;;
|
||||||
|
*)
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
command=${words[i]}
|
||||||
|
elif [[ $command == @(ca|root) && -z $action ]]; then
|
||||||
|
action=${words[i]}
|
||||||
|
else
|
||||||
|
((args++))
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
case $prev in
|
||||||
|
--ca)
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_ca_python cas)" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--template)
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_ca_python templates)" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--reason)
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_ca_python reasons)" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--csr | --pfx | --out)
|
||||||
|
_filedir
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--subject | --san)
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
$split && return
|
||||||
|
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W '--json --help' -- "$cur"))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W 'status list issue revoke maintain ca root' -- "$cur"))
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
local options='--help'
|
||||||
|
case $command$action in
|
||||||
|
list) options+=' --ca' ;;
|
||||||
|
issue) options+=' --ca --template --csr --subject --san --pfx' ;;
|
||||||
|
revoke) options+=' --reason' ;;
|
||||||
|
rootexport-key) options+=' --out' ;;
|
||||||
|
rootremove-key) options+=' --yes' ;;
|
||||||
|
esac
|
||||||
|
COMPREPLY=($(compgen -W "$options" -- "$cur"))
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $command,$action,$args in
|
||||||
|
ca,,*) COMPREPLY=($(compgen -W 'csr import' -- "$cur")) ;;
|
||||||
|
root,,*) COMPREPLY=($(compgen -W 'export-key remove-key import-key import-crl' -- "$cur")) ;;
|
||||||
|
ca,*,0) COMPREPLY=($(compgen -W "$(_vpn_router_ca_python cas)" -- "$cur")) ;;
|
||||||
|
ca,import,1 | root,import-key,0 | root,import-crl,0) _filedir ;;
|
||||||
|
esac
|
||||||
|
} &&
|
||||||
|
complete -F _vpn_router_ca vpn-router-ca
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# bash completion for vpn-router-caddy -*- shell-script -*-
|
||||||
|
|
||||||
|
_vpn_router_caddy()
|
||||||
|
{
|
||||||
|
local cur prev words cword
|
||||||
|
_init_completion || return
|
||||||
|
|
||||||
|
# After the command only --help is left.
|
||||||
|
local word
|
||||||
|
for word in "${words[@]:1:cword-1}"; do
|
||||||
|
if [[ $word != -* ]]; then
|
||||||
|
[[ $cur == -* ]] && COMPREPLY=($(compgen -W '--help' -- "$cur"))
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W '--json --help' -- "$cur"))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W 'status apply use-upstream' -- "$cur"))
|
||||||
|
fi
|
||||||
|
} &&
|
||||||
|
complete -F _vpn_router_caddy vpn-router-caddy
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# bash completion for vpn-router-group -*- shell-script -*-
|
||||||
|
|
||||||
|
# The names of the users and of the groups of the router's directory, read as root; nothing for other users.
|
||||||
|
_vpn_router_group_users()
|
||||||
|
{
|
||||||
|
vpn-router-user --json list 2>/dev/null |
|
||||||
|
python3 -c 'import json, sys; print("\n".join(user["name"] for user in json.load(sys.stdin)["users"]))' 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_vpn_router_group_names()
|
||||||
|
{
|
||||||
|
vpn-router-group --json list 2>/dev/null |
|
||||||
|
python3 -c 'import json, sys; print("\n".join(group["name"] for group in json.load(sys.stdin)["groups"]))' 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_vpn_router_group()
|
||||||
|
{
|
||||||
|
local cur prev words cword split
|
||||||
|
_init_completion -s || return
|
||||||
|
|
||||||
|
# The command is the first word that is not an option; the arguments are the words after it but option values.
|
||||||
|
local i command='' args=0
|
||||||
|
for ((i = 1; i < cword; i++)); do
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
[[ ${words[i]} != -* ]] && command=${words[i]}
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
case ${words[i]} in
|
||||||
|
--member | --description | --name) ((i++)) ;;
|
||||||
|
-*) ;;
|
||||||
|
*) ((args++)) ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W '--json --help' -- "$cur"))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W 'list add update remove member-add member-remove' -- "$cur"))
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $prev in
|
||||||
|
--member)
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_group_users)" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--description | --name)
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
$split && return
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
local options='--help'
|
||||||
|
case $command in
|
||||||
|
add) options+=' --member --description' ;;
|
||||||
|
update) options+=' --name --description' ;;
|
||||||
|
esac
|
||||||
|
COMPREPLY=($(compgen -W "$options" -- "$cur"))
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The group, which add takes new, then the user of member-add and member-remove.
|
||||||
|
if ((args == 0)) && [[ $command != @(list|add) ]]; then
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_group_names)" -- "$cur"))
|
||||||
|
elif ((args == 1)) && [[ $command == member-@(add|remove) ]]; then
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_group_users)" -- "$cur"))
|
||||||
|
fi
|
||||||
|
} &&
|
||||||
|
complete -F _vpn_router_group vpn-router-group
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# bash completion for vpn-router-token -*- shell-script -*-
|
||||||
|
|
||||||
|
_vpn_router_token()
|
||||||
|
{
|
||||||
|
local cur prev words cword split
|
||||||
|
_init_completion -s || return
|
||||||
|
|
||||||
|
case $prev in
|
||||||
|
--minutes | --hours | --days)
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
$split && return
|
||||||
|
|
||||||
|
# The lifetime is one of --minutes, --hours and --days.
|
||||||
|
local options='--json --help' word
|
||||||
|
for word in "${words[@]:1:cword-1}"; do
|
||||||
|
[[ $word == --@(minutes|hours|days)* ]] && break
|
||||||
|
done
|
||||||
|
[[ $word == --@(minutes|hours|days)* ]] || options+=' --minutes --hours --days'
|
||||||
|
COMPREPLY=($(compgen -W "$options" -- "$cur"))
|
||||||
|
} &&
|
||||||
|
complete -F _vpn_router_token vpn-router-token
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
# bash completion for vpn-router-user -*- shell-script -*-
|
||||||
|
|
||||||
|
# The names of the users and of the groups of the router's directory, read as root; nothing for other users.
|
||||||
|
_vpn_router_user_names()
|
||||||
|
{
|
||||||
|
vpn-router-user --json list 2>/dev/null |
|
||||||
|
python3 -c 'import json, sys; print("\n".join(user["name"] for user in json.load(sys.stdin)["users"]))' 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_vpn_router_user_groups()
|
||||||
|
{
|
||||||
|
vpn-router-group --json list 2>/dev/null |
|
||||||
|
python3 -c 'import json, sys; print("\n".join(group["name"] for group in json.load(sys.stdin)["groups"]))' 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_vpn_router_user()
|
||||||
|
{
|
||||||
|
local cur prev words cword split
|
||||||
|
_init_completion -s || return
|
||||||
|
|
||||||
|
local commands='list add update passwd disable enable unlock remove profile otp-new otp-enrol otp-remove console
|
||||||
|
passkeys-remove'
|
||||||
|
|
||||||
|
# The command is the first word that is not an option; the arguments are the words after it but option values.
|
||||||
|
local i command='' args=0
|
||||||
|
for ((i = 1; i < cword; i++)); do
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
[[ ${words[i]} != -* ]] && command=${words[i]}
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
case ${words[i]} in
|
||||||
|
--first-name | --last-name | --email | --display-name | --description | --redirect-uri | \
|
||||||
|
--post-logout-redirect-uri | --allowed-group | --account) ((i++)) ;;
|
||||||
|
-*) ;;
|
||||||
|
*) ((args++)) ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z $command ]]; then
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=($(compgen -W '--json --help' -- "$cur"))
|
||||||
|
else
|
||||||
|
COMPREPLY=($(compgen -W "$commands" -- "$cur"))
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
case $prev in
|
||||||
|
--allowed-group)
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_user_groups)" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--account)
|
||||||
|
# The local accounts console --account takes: a uid from 1000 to 19999, not nobody.
|
||||||
|
COMPREPLY=($(compgen -W "$(getent passwd | awk -F: '$3 >= 1000 && $3 < 20000 && $1 != "nobody" { print $1 }')" -- "$cur"))
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
--first-name | --last-name | --email | --display-name | --description | --redirect-uri | --post-logout-redirect-uri)
|
||||||
|
return
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
$split && return
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
local options='--help'
|
||||||
|
case $command in
|
||||||
|
add) options+=' --first-name --last-name --email --service --display-name --description --redirect-uri
|
||||||
|
--post-logout-redirect-uri --allowed-group' ;;
|
||||||
|
update) options+=' --first-name --last-name --email --display-name --description --redirect-uri
|
||||||
|
--post-logout-redirect-uri --allowed-group' ;;
|
||||||
|
console) options+=' --posix --account --off' ;;
|
||||||
|
esac
|
||||||
|
COMPREPLY=($(compgen -W "$options" -- "$cur"))
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# The user name, which add takes new; otp-enrol then takes a code.
|
||||||
|
if ((args == 0)) && [[ $command != @(list|add) ]]; then
|
||||||
|
COMPREPLY=($(compgen -W "$(_vpn_router_user_names)" -- "$cur"))
|
||||||
|
fi
|
||||||
|
} &&
|
||||||
|
complete -F _vpn_router_user vpn-router-user
|
||||||
|
|
||||||
|
# ex: filetype=sh
|
||||||
Reference in new issue
Block a user