Skip to content

More prosody module tests.#17372

Open
bgrozev wants to merge 52 commits intomasterfrom
claude/youthful-morse-4ea088-2
Open

More prosody module tests.#17372
bgrozev wants to merge 52 commits intomasterfrom
claude/youthful-morse-4ea088-2

Conversation

@bgrozev
Copy link
Copy Markdown
Member

@bgrozev bgrozev commented May 4, 2026

  • Add tests for mod_conference_duration, add module description
  • Extract test context and disco helpers to reduce duplication across spec files
  • Update prosody module docs.
  • Add tests for mod_muc_filter_access using an isolated internal MUC component
  • tests(prosody): add integration tests for mod_muc_resource_validate
  • tests(prosody): use positive presence type assertions
  • tests(prosody): fix presence type assertions and add test:one script
  • tests(prosody): use isAvailablePresence() utility for presence assertions
  • tests(prosody): fix strict mode toggling
  • docs(prosody): add source and usage comment to mod_roster_command
  • fix(prosody): clean up mod_limits_exception; warn on missing async, log config on load
  • test(prosody): add integration tests for mod_muc_census
  • fix(prosody): fix empty array encoding in mod_muc_census; use util.json and util.array
  • refactor(prosody-tests): connect over XMPP WebSocket instead of plain TCP
  • docs(prosody-tests): update README for WebSocket and single-test debug command
  • test(prosody): add integration tests for mod_auth_jitsi-anonymous
  • test(prosody): add mod_auth_jitsi-shared-secret tests
  • test(prosody): add mod_muc_password_whitelist tests
  • fix: Tests hanging.
  • test(prosody): add mod_jitsi_session tests; fix post-test hang
  • test(prosody): switch localhost to token auth; add JWT dependencies
  • test(prosody): add mod_auth_token tests for HS256 shared secret
  • test(prosody): add mod_auth_token ASAP/RS256 tests; make localhost the ASAP host
  • test(prosody): add nbf, context.user, context.group and user_id token tests
  • test(prosody): add mod_filter_iq_jibri feature-authorization tests
  • test(prosody): add mod_filter_iq_rayo integration tests
  • docs(prosody): add module description comments to 6 plugins
  • test(prosody): add mod_token_verification integration tests
  • feat(prosody/tests): run focus as a Prosody admin (focus@auth.localhost)
  • fix(prosody/tests): default sub to '*' in mintAsapToken; drop enable_domain_verification workaround
  • refactor(prosody/tests): consolidate require_token_for_moderation onto conference.localhost
  • fix(prosody-plugins): reject tokens missing the sub claim
  • feat(prosody/tests): add mod_muc_end_meeting integration tests
  • fix(prosody/tests): add sub claim default to buildPayload
  • fix(prosody-plugins): use util.http.formdecode instead of net.url in mod_muc_end_meeting
  • fix(prosody-plugins): block non-focus from creating health-check rooms at pre-create stage
  • test(prosody): add mod_muc_kick_participant integration tests
  • fix(prosody-plugins): fix get_room_from_jid import and status_code in mod_muc_kick_participant
  • docs(prosody-plugins): add structured header comment to mod_system_chat_message
  • test(prosody): add mod_system_chat_message integration tests
  • docs(prosody-plugins): add structured header comment to mod_muc_jigasi_invite
  • test(prosody): add mod_muc_jigasi_invite integration tests
  • refactor(prosody): centralise focus identity checks in util.lib.lua
  • test(prosody): enable anonymous_strict by default; derive MUC nick from JID
  • test(prosody): add mod_end_conference integration tests
  • test(prosody): add mod_muc_auth_ban integration tests

bgrozev added 30 commits May 4, 2026 10:25
Load the module on conference.localhost; toggle anonymous_strict at
runtime via prosodyShell to test strict-mode behaviour without
separate MUC components.
Replace assert.notEqual(type, 'error') with assert.equal(type, 'available')
across all spec files.
Successful join presences have no type attribute (undefined), not
'available'. Also add test:one script for running a single spec file.
…ions

Successful join presences have no type attribute or type="available".
Add isAvailablePresence() to xmpp_utils.js and use it across all specs.
Tests cover: correct secret accepted, any username accepted, wrong
secret rejected. The shared_secret_prev tests are commented out because
get_sasl_handler() only returns shared_secret in its plain callback, so
Prosody rejects any other password; provider.test_password() handles
shared_secret_prev but is not called in the PLAIN SASL flow.

Also adds a comment in the module pointing to the bug.
Tests run against conference.localhost (shared component) to catch
module interference. Covers: whitelisted domain bypasses password,
non-whitelisted domain is rejected, non-whitelisted domain succeeds
with correct password.

Also adds joinRoom password option and setRoomPassword helper to
xmpp_client.js.
Tests verify that URL query params (previd, room, prefix, token,
customusername) are correctly stored on the Prosody session object.
Uses a new /test-observer/session-info endpoint added to
mod_test_observer_http, which captures session fields at resource-bind.

Also adds --exit to .mocharc.cjs to prevent the process from hanging
after all tests complete (@xmpp/reconnect leaves open timer handles).

Also expands the header comment in mod_jitsi_session.lua.
Changes authentication on the localhost VirtualHost to mod_auth_token
with allow_empty_token=true so existing anonymous tests continue to
work while enabling JWT-based tests.

Adds basexx (via luarocks multi-stage build), lua-inspect, and
lua-luaossl to the Docker image, mirroring the production setup in
docker-jitsi-meet.

Updates mod_jitsi_session ?token test to expect auth rejection since
the token is now verified at SASL time.
- Add signature_algorithm and asap_require_room_claim to test Prosody config
- Capture jitsi_meet_room and jitsi_meet_context_features in session-info endpoint
- Add jsonwebtoken dependency and jwt.js helper for minting test tokens
- Add mod_auth_token_spec.js: valid token, wrong secret, expired, wrong issuer,
  context.features, room claim, and empty-token tests
…e ASAP host

- Switch localhost VirtualHost to RS256/ASAP auth (matches production)
- Add hs256.localhost VirtualHost for HS256 shared-secret tests
- Add RSA test key pair and mintAsapToken() helper
- Add mod_auth_token_asap_spec.js: RS256 token tests against localhost
- Update mod_auth_token_spec.js: HS256 tests now target hs256.localhost
- Serve test RSA public key from mod_test_observer_http /asap-keys/ route
- Capture resource-bind on all VirtualHost event buses (not just localhost)
  so session-info works for hs256.localhost sessions too
… tests

- Capture jitsi_meet_context_user and jitsi_meet_context_group in session-info
- Add notYetValid option to mintToken/mintAsapToken for nbf testing
- nbf rejection test in both HS256 and ASAP specs
- context.user, context.group and user_id fallback tests in ASAP spec
- Load mod_filter_iq_jibri on localhost VirtualHost
- Add iq/full hook to mod_test_observer to record Jibri IQs that reach the MUC
  (high priority so it fires before mod_muc consumes the event; filters out
  error/result responses and forwarded copies via type and to_host checks)
- Add GET/DELETE /jibri-iqs endpoints to mod_test_observer_http
- Add sendJibriIq() to xmpp_client helper (fire-and-forget)
- Fix host-activated registration: use hook_global with string arg (not event.host)
  so hs256.localhost sessions are captured after it activates post-localhost
- 18 tests: recording/livestreaming × start/stop × allowed/blocked/absent-key/no-features
  plus status action pass-through for each mode
Tests cover outbound-call and transcription feature gates (allowed,
blocked, absent key, no-features fallback) plus JvbRoomName header
validation (missing, mismatch). Observation via new /dial-iqs HTTP
endpoint backed by mod_test_observer iq/full hook for dial elements.
- Add description comment to mod_token_verification.lua
- Enable token_verification on conference.localhost; allowlist focus.localhost
  so it can create rooms (focus is not a Prosody admin in tests)
- Add VirtualHost test.localhost and Component conference.test.localhost
  for require_token_for_moderation tests; set enable_domain_verification=false
  on both test VirtualHosts since test JWTs carry no sub claim
- Add mod_token_verification_spec.js covering:
  - join access control: anonymous, no-room-claim, matching, mismatched, wildcard
  - require_token_for_moderation: guest blocked, authenticated user allowed
In production jicofo is a Prosody admin, making it exempt from
token_verification and allowing it to act as room owner.  The test
helper was using an anonymous VirtualHost (focus.localhost) and an
explicit token_verification_allowlist as a workaround.

Replace that workaround with the production pattern:
- Add VirtualHost "auth.localhost" (internal_hashed) and pre-create
  focus@auth.localhost via `prosodyctl register` at Docker build time
- Add global `admins = { "focus@auth.localhost" }` so is_admin() returns
  true for the focus client on all components
- Update joinWithFocus() to authenticate with those credentials
- Replace muc_access_whitelist "focus.localhost" → "auth.localhost" so
  focus is still excluded from the occupant limit
- Remove token_verification_allowlist (is_admin exemption covers it)
- Remove VirtualHost "focus.localhost"
…domain_verification workaround

token/util.lib.lua verify_room calls string.lower(session.jitsi_meet_domain)
when enableDomainVerification is true.  If the token has no 'sub' claim
session.jitsi_meet_domain is nil and the call throws a Lua runtime error
that kills the session coroutine, causing a silent 5-second hang instead
of an error response.

Fix: default sub to '*' in mintAsapToken.  The wildcard follows the
existing code path that sets subdomain_to_check = self.muc_domain and
verifies only the room name, so all tests pass without hard-coding a
deployment domain.  With a valid sub claim in every token the
enable_domain_verification = false workaround in the test config can be
removed.
bgrozev added 18 commits May 4, 2026 14:37
…o conference.localhost

Now that focus is a Prosody admin it passes the is_admin() check in the
muc#owner IQ hook, so require_token_for_moderation = true can live on the
main conference.localhost component instead of a dedicated side-car.

- Add token_verification_require_token_for_moderation = true to
  conference.localhost
- Remove VirtualHost "test.localhost" and Component "conference.test.localhost"
- mod_token_verification_spec.js already updated to use conference.localhost
  for both the join-access and moderation test groups
The 'sub' claim carries the domain and is required for domain
verification in verify_room().  Previously a token with no 'sub' would
pass verify_token, set session.jitsi_meet_domain = nil, and then crash
with string.lower(nil) when domain verification ran.

Reject such tokens explicitly in process_and_verify_token(), alongside
the existing requireRoomClaim check.  Add a test that asserts the SASL
connection is refused when sub is absent.
Add a second ASAP key pair (system tokens) separate from the login key
pair, wiring up the full test infrastructure for mod_muc_end_meeting:

- Generate test-system-asap-{private,public}.pem for system tokens.
  mod_muc_end_meeting uses prosody_password_public_key_repo_url (not
  asap_key_server), so login tokens are rejected and system tokens
  cannot be used to log in — key-level separation between user-facing
  and system-facing auth.

- mod_test_observer_http: add GET /test-observer/system-asap-keys/<sha>.pem
  route serving the system public key; refactor key loading into a
  shared load_pem() helper.

- prosody.cfg.lua: load muc_end_meeting globally; set
  muc_mapper_domain_base/prefix and prosody_password_public_key_repo_url
  at global scope (required by the global module).

- Dockerfile: copy system public key into the image.

- jwt.js: export mintSystemToken() (system key, sub:'system.localhost');
  update mintAsapToken() JSDoc to note the key separation.

- test_observer.js: add endMeeting() returning raw { status, body }.

- mod_muc_end_meeting_spec.js: 7 tests covering auth rejection (no
  header, login token, expired token), parameter validation (missing
  conference), and room termination (404 not found, 200 destroy, 200
  silent-reconnect).

- mod_muc_end_meeting.lua: add module description.
mintToken (HS256) was not including a sub claim, causing process_and_verify_token
to reject it after the sub enforcement was added. Move the sub default into
buildPayload so all mint functions (mintToken, mintAsapToken, mintSystemToken)
include it without each needing their own override.
…mod_muc_end_meeting

net.url is not available in the Prosody 13 Docker image used for integration
tests. Prosody's built-in util.http.formdecode provides the same query-string
parsing functionality without an external dependency.
…s at pre-create stage

When a non-focus user is the first to attempt joining a health-check room,
muc-room-pre-create fires before the room exists. mod_token_verification runs
at priority 99 on that event and calls verify_room, which returns room-does-not-
exist (the room isn't created yet), causing a not-allowed error instead of the
expected service-unavailable.

Add a muc-room-pre-create hook at priority 100 so it runs first and sends the
correct service-unavailable error for non-focus joins to health-check rooms.
… mod_muc_kick_participant

Two bugs: get_room_from_jid was called without being imported from util (causing
a nil call error at runtime), and the error branch returned { error_code = 400 }
instead of { status_code = error_code }, which Prosody ignores (unknown key),
causing the endpoint to return HTTP 200 on validation failures.
Covers authentication (401 for missing/login/expired token), parameter
validation (400 for bad content-type, empty body, missing fields), room
lookup (404), and message delivery (payload content, displayName, multiple
recipients). Adds sendSystemChatMessage helper to test_observer.js and
waitForMessage to the xmpp client.
Covers authentication (401 for missing/login/expired token), parameter
validation (400 for bad content-type, empty body, missing fields), and the
brewery-room-not-found 404 path. Adds a minimal internal.auth.localhost MUC
component to the test Prosody config so the module's process_host_module
callback fires and main_muc_service is initialised before requests arrive.
Add is_focus_nick() and is_focus_jid() alongside the existing is_focus()
and replace all ad-hoc focus checks scattered across plugins with these
three utility functions.
…om JID

Set anonymous_strict = true in the test Prosody config so all token/anonymous
clients must use the first 8 characters of their server-assigned JID as their
MUC resource.

xmpp_client.js: joinRoom() now defaults the nick to the JID-derived UUID prefix
instead of a counter-based name. A nick getter on the client object exposes
the same value so tests can reference it after joining.

All test files that passed explicit nicks for anonymous clients are updated to
use the default (or to derive the nick from client.nick where the nick must be
known to a subsequent HTTP call). Tests that specifically cover format-invalid
nicks (_invalid, invalid-nick) are unaffected since the format check runs
before the UUID-prefix check. Tests that cover arbitrary valid nicks temporarily
disable strict mode via setStrictMode(false) to isolate format-only behavior.
Configure an endconference.localhost component and add mod_jitsi_session to
global modules so that clients can set jitsi_web_query_room via ?room= URL
param, which mod_end_conference uses to locate the target MUC room.

Add grantModerator(), sendEndConference(), sendPlainMessage(), and
waitForPresence() helpers to the XMPP test client.

Five tests cover: moderator destroys room, all occupants receive unavailable
presence with destroy element, non-moderator rejected, non-occupant rejected,
plain message without <end_conference/> ignored.

Moderator role is granted via an explicit admin IQ from focus rather than from
token claims; a TODO notes that this should be replaced once the relevant
module is available in the test environment.
Add a mock access manager HTTP endpoint to mod_test_observer_http and
wire up mod_muc_auth_ban in the test Prosody config pointing at it.

Tests cover: no-token allowed, non-VPaaS bypass, VPaaS access=true
allowed, VPaaS access=false rejected (SASL failure), LRU cache
prevents HTTP re-check after ban, HTTP error fails open.
38 busted tests covering config validation, credentials handler error
paths, service entry shape, and all generateToken JWT payload claims.
local array = require 'util.array';
local jid = require "util.jid";
local json = require 'cjson.safe';
local json = require 'util.json';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the change? cjson is more optimized and we switched to using it.

-- plugin, invoked at provisioning time via:
-- prosodyctl mod_roster_command subscribe <jid1> <jid2>
-- Used by Ansible to subscribe focus.<domain> to focus@auth.<domain>.
-----------------------------------------------------------
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth mentioning we need it for prosody 0.12 and can drop it once we support only 13.

bgrozev added 4 commits May 5, 2026 11:53
- Enable mod_muc_flip on the test conference component
- Add inspect.lua stub to Docker image (required by several Jitsi plugins)
- Add POST /sessions/context endpoint to mod_test_observer_http so tests
  can inject JWT context (user id + features) onto live sessions without
  a real token-auth module
- Add GET /rooms/participants endpoint exposing mod_muc_flip's
  participants_details and kicked/flip nick fields
- Extend joinRoom() to accept extra presence children (e.g. <flip_device/>)
- Add waitForPresenceFrom() to watch for specific presence stanzas
- Add setSessionContext() and getRoomParticipants() JS helpers
- 7 integration tests covering: tag stripping for guests, tag stripping
  when feature disabled, tag stripping when user not in room,
  participants_details tracking on join/leave, flip kick, and
  flip_device tag on kicked occupant's unavailable presence
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants