refactor: extract guest session helpers

The __party_guest_$user session name was spelled out in cmd_join,
cmd_leave, cmd_status, cmd_role, and _disconnect_user. Add
guest_session_name to print it consistently. Add ensure_guest_session
for the has-session/new-session snippet duplicated in cmd_join and
cmd_role. Add caller_present_on for the client-or-guest-session OR
duplicated in cmd_leave and cmd_status.
This commit is contained in:
veg 2026-09-21 09:41:31 +00:00
parent 9544f605a6
commit fb92ea1ae7

85
party
View file

@ -398,6 +398,42 @@ party_conn_state() {
fi fi
} }
# Guest sessions
# --------------
# Print the caller's guest session name for a given user: the fixed
# session __party_guest_<user> that join/leave/status/role/kick/detach
# all target.
guest_session_name() {
printf '__party_guest_%s\n' "$1"
}
# Ensure the caller's guest session exists on <sock>, creating it off
# <host_session> if needed. Leaves the session name in `guest` for the
# caller.
#
# Reusing by name is an accepted insider risk, not a defended one: any
# write-capable invitee can pre-create a session called
# __party_guest_$USER (and even group it to the party), so on a shared
# server no session name is unforgeable. We trust invitees by design,
# that's the whole model. A read-only invitee (-r) can't create
# sessions, so it's not exposed. See README §Trust model.
ensure_guest_session() {
_eg_sock="$1" _eg_host_sess="$2"
guest=$(guest_session_name "$USER")
"$PARTY_TMUX" -S "$_eg_sock" has-session -t "$guest" 2>/dev/null \
|| "$PARTY_TMUX" -S "$_eg_sock" new-session -d -t "$_eg_host_sess" -s "$guest"
}
# Boolean: does the caller have any presence on the party at <sock>,
# either an attached client or an owned guest session? Only meaningful
# when party_conn_state is `ok`; callers gate on that themselves.
caller_present_on() {
"$PARTY_TMUX" -S "$1" list-clients -F '#{client_user}' 2>/dev/null \
| grep -qx "$USER" \
|| "$PARTY_TMUX" -S "$1" has-session -t "$(guest_session_name "$USER")" 2>/dev/null
}
# FS perms # FS perms
# -------- # --------
# #
@ -1267,17 +1303,7 @@ EOF
# An active guest session survives a client detach, so create it # An active guest session survives a client detach, so create it
# only if it isn't already there, a plain new-session on re-join # only if it isn't already there, a plain new-session on re-join
# would hit "duplicate session" and abort under set -e. # would hit "duplicate session" and abort under set -e.
# ensure_guest_session "$RR_SOCKET" "$RR_PARTY_NAME"
# Reusing by name is an accepted insider risk, not a defended one:
# any write-capable invitee can pre-create a session called
# __party_guest_$USER (and even group it to the party), so on a
# shared server no session name is unforgeable. We trust invitees
# by design, that's the whole model. A read-only invitee (-r)
# can't create sessions, so it's not exposed. See README §Trust
# model.
guest="__party_guest_$USER"
"$PARTY_TMUX" -S "$RR_SOCKET" has-session -t "$guest" 2>/dev/null \
|| "$PARTY_TMUX" -S "$RR_SOCKET" new-session -d -t "$RR_PARTY_NAME" -s "$guest"
set -- attach-session -t "$guest" set -- attach-session -t "$guest"
fi fi
@ -1314,17 +1340,13 @@ cmd_leave() {
found=0 found=0
for rec in $(roster_list); do for rec in $(roster_list); do
roster_read "$rec" || continue roster_read "$rec" || continue
# Presence checks below (has-session, list-clients) are only # Presence checks inside caller_present_on (has-session,
# meaningful on a server that accepted our connection: for an # list-clients) are only meaningful on a server that accepted
# unauthorized caller has-session answers rc 0 for ANY target, # our connection: for an unauthorized caller has-session answers
# which made leave "succeed" against parties we never joined. # rc 0 for ANY target, which made leave "succeed" against
# parties we never joined.
[ "$(party_conn_state "$RR_SOCKET")" = ok ] || continue [ "$(party_conn_state "$RR_SOCKET")" = ok ] || continue
attached=0 caller_present_on "$RR_SOCKET" || continue
"$PARTY_TMUX" -S "$RR_SOCKET" has-session -t "__party_guest_$USER" 2>/dev/null \
&& attached=1
"$PARTY_TMUX" -S "$RR_SOCKET" list-clients -F '#{client_user}' 2>/dev/null \
| grep -qx "$USER" && attached=1
[ "$attached" = 1 ] || continue
_disconnect_user "$USER" _disconnect_user "$USER"
found=$((found+1)) found=$((found+1))
done done
@ -1512,7 +1534,7 @@ cmd_mute() { _set_user_access mute -r Muted "$@"; }
# their guest session if present. Used by both cmd_kick and cmd_detach. # their guest session if present. Used by both cmd_kick and cmd_detach.
_disconnect_user() { _disconnect_user() {
user="$1" user="$1"
"$PARTY_TMUX" -S "$RR_SOCKET" kill-session -t "__party_guest_$user" 2>/dev/null || true "$PARTY_TMUX" -S "$RR_SOCKET" kill-session -t "$(guest_session_name "$user")" 2>/dev/null || true
"$PARTY_TMUX" -S "$RR_SOCKET" list-clients -F '#{client_name} #{client_user}' 2>/dev/null \ "$PARTY_TMUX" -S "$RR_SOCKET" list-clients -F '#{client_name} #{client_user}' 2>/dev/null \
| while read -r cname cuser; do | while read -r cname cuser; do
[ "$cuser" = "$user" ] || continue [ "$cuser" = "$user" ] || continue
@ -1674,14 +1696,10 @@ cmd_status() {
[ "$state" = ok ] || continue [ "$state" = ok ] || continue
# Joined covers two cases. Passive: we have a client attached to # Joined covers two cases. Passive: we have a client attached to
# the host's session, list-clients sees it. Active: we have our # the host's session, list-clients sees it. Active: we have our
# own __party_guest_$USER session, which survives a client detach # own guest session, which survives a client detach (party leave
# (party leave will still find and clean it up). OR the two so a # will still find and clean it up). caller_present_on ORs the
# detached active guest still reports as joined. # two so a detached active guest still reports as joined.
if "$PARTY_TMUX" -S "$RR_SOCKET" list-clients -F '#{client_user}' \ if caller_present_on "$RR_SOCKET"; then
2>/dev/null | grep -qx "$USER" \
|| "$PARTY_TMUX" -S "$RR_SOCKET" has-session \
-t "__party_guest_$USER" 2>/dev/null
then
joined="$joined $RR_PARTY_NAME" joined="$joined $RR_PARTY_NAME"
fi fi
done done
@ -1739,15 +1757,12 @@ EOF
done done
fi fi
[ -n "$sock" ] || { echo "party role: not attached to any party." >&2; exit 1; } [ -n "$sock" ] || { echo "party role: not attached to any party." >&2; exit 1; }
guest="__party_guest_$USER" guest=$(guest_session_name "$USER")
# active and switch may switch a client INTO the guest session; create # active and switch may switch a client INTO the guest session; create
# it on demand. passive and the no-arg print path don't need it. # it on demand. passive and the no-arg print path don't need it.
case "$sub" in case "$sub" in
active|switch) active|switch) ensure_guest_session "$sock" "$host_sess" ;;
"$PARTY_TMUX" -S "$sock" has-session -t "$guest" 2>/dev/null \
|| "$PARTY_TMUX" -S "$sock" new-session -d -t "$host_sess" -s "$guest"
;;
esac esac
"$PARTY_TMUX" -S "$sock" list-clients \ "$PARTY_TMUX" -S "$sock" list-clients \