diff options
| author | EuAndreh <eu@euandre.org> | 2026-04-30 09:30:02 -0300 |
|---|---|---|
| committer | EuAndreh <eu@euandre.org> | 2026-04-30 09:30:02 -0300 |
| commit | 35c93a4da10124ba1a8ca9b0a316150136d49eac (patch) | |
| tree | 74922eaa29c28a70e4615e40e921a609f861b67e /src | |
| parent | Honor userhost-in-names and account-tag caps end-to-end (diff) | |
| download | papod-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.clj | 34 |
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?) |
