summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2026-04-30 09:30:02 -0300
committerEuAndreh <eu@euandre.org>2026-04-30 09:30:02 -0300
commit35c93a4da10124ba1a8ca9b0a316150136d49eac (patch)
tree74922eaa29c28a70e4615e40e921a609f861b67e /src
parentHonor userhost-in-names and account-tag caps end-to-end (diff)
downloadpapod-35c93a4da10124ba1a8ca9b0a316150136d49eac.tar.gz
papod-35c93a4da10124ba1a8ca9b0a316150136d49eac.tar.xz
Honor CAP REQ -cap and ignore unknown batch refs
Two compliance gaps surfaced by the chat.papo.im integration suite: - CAP REQ :-echo-message previously matched no supported cap name (because of the leading '-'), so it was NAKed; even when a client sent a plain disable like above, papod silently kept the cap in the active set. We now split each REQ token by the '-' prefix, mark it as :add or :remove, and update the client's cap set accordingly. An REQ containing a mix of known and unknown caps is still NAKed atomically. - A message tagged with @batch=X referring to a batch that was never opened (e.g. because handle-batch-open! rejected the BATCH because of a missing target) used to fall through into normal command processing — so a malformed multiline batch would still deliver its inner PRIVMSG. Per IRCv3 we now silently drop those messages instead.
Diffstat (limited to 'src')
-rw-r--r--src/papod.clj34
1 files changed, 24 insertions, 10 deletions
diff --git a/src/papod.clj b/src/papod.clj
index d5b6f20..35b9b49 100644
--- a/src/papod.clj
+++ b/src/papod.clj
@@ -1502,12 +1502,23 @@
"draft/channel-rename"
"draft/extended-isupport"
"draft/metadata-2"
- "draft/typing"}]
- (if-not (every? supported requested)
+ "draft/typing"}
+ split (fn [c] (if (string/starts-with? c "-")
+ [(subs c 1) :remove]
+ [c :add]))
+ split-reqs (map split requested)
+ all-known? (every? (fn [[name _]]
+ (supported name))
+ split-reqs)]
+ (if-not all-known?
[(str ":" +server-name+ " CAP " nick
" NAK :" raw-args)]
- (do (swap! client update :caps
- (fnil into #{}) requested)
+ (do (doseq [[name op] split-reqs]
+ (swap! client update :caps
+ (fn [s]
+ (case op
+ :add (conj (or s #{}) name)
+ :remove (disj (or s #{}) name)))))
[(str ":" +server-name+ " CAP " nick
" ACK :" raw-args)])))
@@ -4975,13 +4986,16 @@
(string/starts-with? c ":") (subs 1))))
blank? (and content (empty? content))]
(cond
- ;; Tagged with a batch ID we don't know about, while
- ;; another batch is open: protocol violation.
- (and batch-tag (not in-batch) any-batch-open?)
+ ;; Tagged with a batch ID we don't know about: per IRCv3
+ ;; the message MUST be ignored (the batch was rejected or
+ ;; never existed). We additionally clear any other open
+ ;; batches when one was open, since this is a sign the
+ ;; client got out of sync.
+ (and batch-tag (not in-batch))
(do
- (swap! client dissoc :batches)
- [(str "FAIL BATCH MULTILINE_INVALID"
- " :Batch tag does not match")])
+ (when any-batch-open?
+ (swap! client dissoc :batches))
+ [])
;; Concat tag on a blank message: invalid per spec.
(and in-batch concat-tag? blank?)