Forum teuk.org

πŸšͺ Mediabot 3.4dev β€” Expulso now obeys every ward of the Great Hall πŸ”πŸͺ„

in Mediabot Β· started by TeuK Β· 4w ago

TeuK Β· 4w ago

Mediabot v3 continues its 3.4 development cycle with a new moderation capability for the external script bridge.

Scripts could already reply, send notices, write logs, arm timers and update their own channel topic. They can now also request the removal of an abusive user through a new kick action.

Because this is a moderation command, the implementation is deliberately narrower and more defensive than an ordinary IRC reply.

πŸͺ„ A sixth spell in the bridge protocol

A script may now return:

{"type":"kick","nick":"Intruder","reason":"spam"}

The bridge validates the action, applies its permission gates and, when every condition is satisfied, emits a real IRC KICK.

The script cannot supply a channel target.

The destination is always the channel that produced the event or command. Cross-channel kicking does not exist in the protocol, so there is no hidden option to misconfigure later.

In Hogwarts terms: the porter may remove someone from the Great Hall, but cannot point the spell through a wall into another room.

πŸ” Three locked gates

A real kick requires all three permissions:

ACTION_MODE=apply
ALLOW_IRC=yes
ALLOW_KICK=yes

ALLOW_KICK defaults to no.

The setting is part of the bridge configuration fingerprint, so it can be changed with the existing hot-reload workflow.

Every closed gate produces a distinct error. Dry-run mode can validate and plan the action, but never sends it to IRC.

The moderation spell is therefore disabled twice by default:

  • no explicit matching rule means no kick request;
  • no explicit ALLOW_KICK=yes means no IRC kick.

πŸ§™ gatekeeper.pl β€” the quiet porter

The new reference example is:

plugins/scripts/examples/gatekeeper.pl

A typical route can look like:

EVENTS=join=examples/gatekeeper.pl
CONFIG_join=kick_substrings=spambot flood;kick_reason=not welcome here

The script performs a case-insensitive substring match against the joining nick.

It deliberately does not accept operator-provided regular expressions. That keeps the configuration easy to understand and avoids surprising or expensive regex behavior.

Normal joins produce no output.

A good porter does not announce every honest visitor. It only acts when a configured rule matches.

With no configured pattern, the script remains completely disarmed.

πŸ›‘οΈ The bot cannot expel itself

Before a kick reaches the IRC writer, Mediabot verifies that the requested nick is not its own current nick.

The final hardening makes this protection fail-closed.

If the IRC layer cannot reliably identify the bot, or if the identity check fails, the kick is rejected instead of being allowed through.

The result is simple:

identity cannot be verified
β†’ no KICK is sent

No script, configuration mistake or exceptional path should be able to make the castle porter throw out the headmaster.

🎯 Channel scope is canonical and strict

The bridge now stores the real channel token rather than a decorated status-message target.

For example:

@#channel

is reduced to:

#channel

before the IRC command is built.

Malformed channel contexts are rejected before they can reach send_message.

This applies the same scope discipline already used by the hardened topic action.

πŸͺͺ IRC nickname grammar is enforced

The kick target is not merely checked against a bag of allowed characters.

The first character must follow IRC nickname rules and cannot be a digit or a hyphen.

Values such as:

123
-intruder

are rejected before application.

Nick length remains bounded to 30 characters.

🌍 Unicode reasons are safe on the wire

Kick reasons are decoded from JSON as Perl character strings.

The final path now encodes them to UTF-8 bytes before they reach the asynchronous IRC writer, matching the existing protection for reply, notice and topic actions.

A reason such as:

spam au cafΓ© πŸͺ„

can therefore reach IRC without triggering a wide-character write failure.

The limit is enforced as 120 UTF-8 bytes rather than 120 abstract characters, so the documented boundary matches the actual wire payload.

πŸ“œ Logs describe requests, not imaginary success

The reference script originally logged that it was β€œkicking” a user immediately after producing the action.

That wording could become false when a gate rejected the request, the self-check failed or the IRC send returned an error.

The log now says:

gatekeeper: kick requested for ...

That remains truthful regardless of the final application result.

The bridge owns the outcome. The script records only what it requested.

πŸ§ͺ Validation

The Claude implementation reported:

10912/10912 tests passed

before the final scope, nickname, UTF-8 and identity hardening.

The extended regression contract adds coverage for:

  • the three kick gates;
  • hot reload of ALLOW_KICK;
  • originating-channel-only scope;
  • STATUSMSG channel canonicalization;
  • malformed channel rejection;
  • IRC nickname first-character rules;
  • UTF-8 byte limits;
  • Unicode wire encoding;
  • self-kick refusal;
  • fail-closed identity verification;
  • truthful gatekeeper logging;
  • real join-to-KICK behavior;
  • silence for ordinary joins.

The final full suite, security audit, startup integrity check and CI should remain the release gate before publication.

No database schema change.
No default moderation rule.
No kick permission enabled automatically.

πŸ§™ Summary

This round turns the script bridge into a carefully bounded moderation tool:

  • scripts may request a kick only in their own channel;
  • three independent gates protect every real action;
  • the feature is disabled by default;
  • nicknames and reasons are validated against IRC reality;
  • Unicode is encoded safely;
  • malformed or decorated targets cannot escape validation;
  • bot identity checks fail closed;
  • the reference gatekeeper remains silent until explicitly armed;
  • logs never claim an action succeeded before the bridge applies it.

Expulso has entered the Mediabot spellbookβ€”but every corridor, lock and protective ward must agree before the Great Hall door opens. πŸšͺπŸ”πŸͺ„

You must be logged in to reply.