Implement an advanced registration loop to begin supporting multiple registration methods

This commit is contained in:
Nick Chambers 2021-11-27 23:55:00 -06:00
parent 7cdff45600
commit bea7df3390
1 changed files with 170 additions and 22 deletions

192
rowbot
View File

@ -354,12 +354,14 @@ state_resolve() {
# This is a false positive.
# shellcheck disable=SC2102
if [[ -v config[$1] ]]; then
ns_config[$1]=${config[$1]}
elif [[ -v config[$ns-$1] ]]; then
if [[ -v config[$ns-$1] ]]; then
ns_config[$1]=${config[$ns-$1]}
elif [[ -v config[$1] ]]; then
ns_config[$1]=${config[$1]}
elif [[ -v DEFAULT ]]; then
ns_config[$1]=$DEFAULT
elif [[ -v DEFAULT_N && $DEFAULT_N ]]; then
ns_config[$1]=$DEFAULT_N
else
return 1
fi
@ -400,6 +402,17 @@ state_get() {
fi
}
state_keys() {
# The `ns_config` variable is a reference to an array
# shellcheck disable=SC2178
declare -n ns_config=__rowbot_state_store_"${NS-global}"
declare -n array_keys=${1-CONFIG_KEYS}
# The `array_keys` variable initializes a variable declared by the calling
# code.
# shellcheck disable=SC2034
array_keys=( "${!ns_config[@]}" )
}
state_has() {
local ns=${NS-global} found=1 managed
# The `ns_config` variable is a reference to an array
@ -736,6 +749,103 @@ on_sys_exit_997_annoyatron900() {
# register with the server
###
on_sys_first_020_enroll() {
NS=enroll state_resolve caps
NS=enroll state_resolve pass
NS=irc DEFAULT=rowbot-dev state_resolve nick
NS=irc DEFAULT=rowbot state_resolve ident
NS=irc DEFAULT=rowbot state_resolve realname
log_debug "beginning irc registration handshake"
if NS=enroll state_has caps; then
log_debug "requesting list of available capabilities"
irc_cap ls
fi
if NS=enroll state_has pass; then
log_debug "sending account password"
irc_pass "$(NS=enroll state_get pass)"
fi
log_debug "sending registration data"
irc_nick "$(NS=irc state_get nick)"
irc_user "$(NS=irc state_get ident)" "$(NS=irc state_get realname)"
}
on_msg_CAP_enroll() {
local avail_cap{s,} desired_cap{s,} caps mechanism advertised
if NS=enroll state_has caps; then
case ${msg_args[1]^^} in
LS)
if ! NS=enroll QUIET="" state_get requested-caps; then
NS=avail_caps state_keys avail_caps
read -ra desired_caps < <(NS=enroll state_get caps)
# The `avail_caps` array gets initialized in the state_keys function.
# shellcheck disable=SC2154
for avail_cap in "${avail_caps[@]}"; do
for desired_cap in "${desired_caps[@]}"; do
if [[ $avail_cap = "$desired_cap" ]]; then
caps+=( "$avail_cap" )
NS=caps state_put "$avail_cap" ""
fi
done
done
irc_cap req "${caps[@]}"
NS=enroll state_put requested-caps yes
fi
;;
NAK)
irc_cap end
NS=enroll state_put have-caps no
;;
ACK)
NS=enroll state_put have-caps yes
if NS=caps state_has sasl; then
if NS=enroll state_has pass; then
mechanism=plain
elif NS=net QUIET="" state_get tls && NS=net state_has client-cert; then
mechanism=external
fi
NS=sasl DEFAULT_N=$mechanism state_resolve mechanism
NS=sasl DEFAULT=yes state_resolve required
if ! NS=sasl state_has mechanism; then
die "please specify an appropriate sasl mechanism"
fi
advertised=$(NS=avail_caps state_get sasl)
mechanism=$(NS=sasl state_get mechanism)
if [[ ,$advertised, = *,"${mechanism^^}",* ]]; then
irc_authenticate mechanism "$(NS=sasl state_get mechanism)"
else
if NS=sasl QUIET="" state_get required; then
die "%s is not a valid sasl mechanism" "$mechanism"
else
log_warn "connecting without sasl"
irc_cap end
fi
fi
else
irc_cap end
fi
esac
fi
}
on_msg_AUTHENTICATE_enroll() {
# Any fail scenario is already covered.
# shellcheck disable=SC2155
local mechanism=$(NS=sasl state_get mechanism)
irc_authenticate +
}
on_sys_init_010_bootup() {
DEFAULT=${USER:-uplime} state_resolve owner
DEFAULT=\` state_resolve trigger
@ -746,15 +856,6 @@ on_sys_init_020_welcome() {
NS=irc state_resolve chans
}
on_sys_first_020_welcome() {
NS=irc DEFAULT=rowbot-dev state_resolve nick
NS=irc DEFAULT=rowbot state_resolve ident
NS=irc DEFAULT=rowbot state_resolve realname
log_debug "registering with the server"
irc_nick "$(NS=irc state_get nick)"
irc_user "$(NS=irc state_get ident)" "$(NS=irc state_get realname)"
}
on_msg_005_welcome() {
local param key value
@ -797,6 +898,35 @@ on_msg_396_privmagic() {
# irc receive handlers
###
irc_on_AUTHENTICATE() {
log_debug "received authentication acknowledgement"
}
irc_on_CAP() {
local cap caps
case ${msg_args[1]^^} in
LS)
caps=${msg_args[-1]}
while [[ $caps ]]; do
cap=${caps%% *} caps=${caps#"$cap"} caps=${caps# }
if [[ $cap = *=* ]]; then
NS=avail_caps state_put "${cap%%=*}" "${cap#*=}"
else
NS=avail_caps state_put "$cap" ""
fi
done
;;
NAK)
log_error "unable to request capabilities for %s" "$(NS=irc state_get nick)"
;;
ACK)
log_debug "have successfully received capabilities from server: %s" "${msg_args[-1]}"
esac
}
irc_on_ERROR() {
log_error "${msg_args[0]}"
exit
@ -983,6 +1113,30 @@ irc_accept() {
net_send "ACCEPT $1"
}
irc_authenticate() {
case ${1,,} in
mechanism)
net_send "AUTHENTICATE %s" "${2^^}"
;;
*)
net_send "AUTHENTICATE %s" "$*"
esac
}
irc_cap() {
case ${1,,} in
ls)
net_send "CAP LS %s" "${2-302}"
;;
req)
shift
net_send "CAP REQ :%s" "$*"
;;
end)
net_send "CAP END"
esac
}
irc_join() {
local chans
printf -v chans %s, "$@"
@ -1027,6 +1181,10 @@ irc_part() {
fi
}
irc_pass() {
net_send "PASS $1"
}
irc_ping() {
net_send "PING :%s" "$1"
}
@ -1053,16 +1211,6 @@ irc_privmsg() {
log_info "<%s/%s> %s" "${config[nick]}" "$1" "$msg"
}
irc_part() {
if (( $# )); then
if (( $# > 1 )); then
net_send "PART $1 :$2"
else
net_send "PART $1"
fi
fi
}
irc_quit() {
if (( $# )); then
net_send "QUIT :%s" "$1"