fix: reject '.' and leading '-' in party names

tmux session_check_name() silently rewrites '.' to '_', so a dotted
party name desyncs from its tmux session and every -t lookup fails
(verified on tmux 3.3a through 3.6b). Leading-dash names can never be
addressed through the CLI parsers.
This commit is contained in:
veg 2026-07-04 07:51:38 +00:00
parent a4e6dbe672
commit f06c599ea7
2 changed files with 37 additions and 17 deletions

39
party
View file

@ -65,30 +65,32 @@ EOF
# Helpers # Helpers
# ======= # =======
# Validate a party name. Accepts [A-Za-z0-9._-]{1,63}. Reject empty, # Validate a party name. Accepts [A-Za-z0-9_-]{1,63}, not starting with
# paths, shell metas, and overlong names: the name lands in a file # '-'. Reject empty, paths, shell metas, and overlong names: the name
# path component, a tmux session name, and shell command lines. # lands in a file path component, a tmux session name, and shell
# command lines. Dots are rejected because tmux's session_check_name()
# silently rewrites '.' (and ':') to '_', which would desync the party
# name from its tmux session and break every later `-t <name>` target.
# Leading '-' is rejected because every subcommand parser would eat the
# name as a flag, so such a party could never be addressed.
validate_party_name() { validate_party_name() {
name="$1" name="$1"
case "$name" in case "$name" in
'' ) echo "party: name must not be empty" >&2; return 2 ;; '' ) echo "party: name must not be empty" >&2; return 2 ;;
esac esac
# Length cap: 63 keeps the full /tmp/party-${USER}-${name} comfortably # Length cap: 63 keeps the full socket path comfortably below the
# below the 108-char sun_path limit for typical USERs. # 108-char sun_path limit for typical USERs.
if [ "${#name}" -gt 63 ]; then if [ "${#name}" -gt 63 ]; then
echo "party: name '$name' too long (max 63 chars)" >&2 echo "party: name '$name' too long (max 63 chars)" >&2
return 2 return 2
fi fi
case "$name" in case "$name" in
*[!A-Za-z0-9._-]* ) -* )
echo "party: name '$name' has invalid characters" >&2 echo "party: name must not start with '-'" >&2
echo " allowed: letters, digits, '.', '_', '-'" >&2
return 2 ;; return 2 ;;
esac *[!A-Za-z0-9_-]* )
# Reject ".", "..", and any leading-dot variant we don't want. echo "party: name '$name' has invalid characters" >&2
case "$name" in echo " allowed: letters, digits, '_', '-'" >&2
.|.. )
echo "party: name '$name' is reserved" >&2
return 2 ;; return 2 ;;
esac esac
return 0 return 0
@ -237,10 +239,13 @@ roster_read() {
[ -n "$RR_PARTY_NAME" ] || return 1 [ -n "$RR_PARTY_NAME" ] || return 1
# Pattern parity with cmd_host. The basename glob (party-*:*.d) is # Pattern parity with cmd_host. The basename glob (party-*:*.d) is
# permissive, names like '.' (basename party-USER:..d) or 'a b' # permissive — names like 'a b' or 'my.party' match the glob but
# match the glob but validate_party_name rejects them. Run the # validate_party_name rejects them (dots are banned: tmux rewrites
# canonical validator so the invariant cmd_host enforces on write # them in session names). Run the canonical validator so the
# is also checked on read. # invariant cmd_host enforces on write is also checked on read.
# Side effect: pre-existing dotted-party dirs from older builds
# become undiscoverable, which is the pre-release migration policy
# (README §Status).
validate_party_name "$RR_PARTY_NAME" 2>/dev/null || return 1 validate_party_name "$RR_PARTY_NAME" 2>/dev/null || return 1
# Both the dir and its sock must be owned by the user named in the # Both the dir and its sock must be owned by the user named in the

View file

@ -42,6 +42,21 @@ setup() {
done done
} }
@test "validate_party_name rejects dots (tmux rewrites '.' in session names)" {
# tmux session_check_name() silently maps '.' and ':' to '_', so a
# dotted party name desyncs from its tmux session and every later
# `-t <name>` target fails. Verified on tmux 3.3a through 3.6b.
for bad in "my.party" "." ".." "a.d"; do
run validate_party_name "$bad"
[ "$status" -ne 0 ] || { echo "should have rejected: $bad"; false; }
done
}
@test "validate_party_name rejects leading dash (unusable through the CLI)" {
run validate_party_name "-flag"
[ "$status" -ne 0 ]
}
# time # time
# ==== # ====