Files
upstream-jitsi-meet/tests/prosody/mod_token_affiliation_spec.js
upstream-mirror 1d2bfcac0c
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s
snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
2026-09-15 15:56:32 +05:00

166 lines
5.8 KiB
JavaScript

import assert from 'assert';
import { mintAsapToken } from './helpers/jwt.js';
import { createXmppClient, joinWithFocus } from './helpers/xmpp_client.js';
const CONFERENCE = 'conference.localhost';
const MUC_NS = 'http://jabber.org/protocol/muc#user';
let _counter = 0;
const nextRoom = () => `affiliation-${++_counter}@${CONFERENCE}`;
/**
* Extracts the role and affiliation from a self-presence stanza.
*
* @param {object} presence
* @returns {{ role: string|null, affiliation: string|null }}
*/
function getRoleAndAffiliation(presence) {
const item = presence.getChild('x', MUC_NS)?.getChild('item');
return {
role: item?.attrs.role ?? null,
affiliation: item?.attrs.affiliation ?? null
};
}
/**
* Connects a client on the main VirtualHost with the given context.user claims
* embedded in a RS256 token scoped to the given room.
*
* @param {string} roomJid full room JID, e.g. 'room@conference.localhost'
* @param {object} contextUser JWT context.user payload.
* @returns {Promise<XmppTestClient>}
*/
function connectWithToken(roomJid, contextUser) {
const roomName = roomJid.split('@')[0];
const token = mintAsapToken({ room: roomName,
context: { user: contextUser } });
return createXmppClient({ params: { token } });
}
describe('mod_token_affiliation', () => {
const clients = [];
afterEach(async () => {
await Promise.all(clients.map(c => c.disconnect()));
clients.length = 0;
});
// -------------------------------------------------------------------------
// Moderator claim variants
// -------------------------------------------------------------------------
describe('moderator claim variants that grant owner/moderator', () => {
/**
* Asserts that a client with the given JWT context user receives owner/moderator.
* @param {object} contextUser JWT context.user payload.
*/
async function assertModerator(contextUser) {
const r = nextRoom();
clients.push(await joinWithFocus(r));
const c = await connectWithToken(r, contextUser);
clients.push(c);
const presence = await c.joinRoom(r);
const { role, affiliation } = getRoleAndAffiliation(presence);
assert.equal(affiliation, 'owner', `expected affiliation=owner, got ${affiliation}`);
assert.equal(role, 'moderator', `expected role=moderator, got ${role}`);
}
it('moderator=true (boolean)', () => assertModerator({ moderator: true }));
it('moderator=\'true\' (string)', () => assertModerator({ moderator: 'true' }));
it('affiliation=\'owner\'', () => assertModerator({ affiliation: 'owner' }));
it('affiliation=\'moderator\'', () => assertModerator({ affiliation: 'moderator' }));
it('affiliation=\'teacher\'', () => assertModerator({ affiliation: 'teacher' }));
});
// -------------------------------------------------------------------------
// Member (authenticated, non-moderator)
// -------------------------------------------------------------------------
it('grants member affiliation and participant role for authenticated non-moderator', async () => {
const r = nextRoom();
clients.push(await joinWithFocus(r));
const c = await connectWithToken(r, { id: 'user1' });
clients.push(c);
const presence = await c.joinRoom(r);
const { role, affiliation } = getRoleAndAffiliation(presence);
assert.equal(affiliation, 'member', `expected affiliation=member, got ${affiliation}`);
assert.equal(role, 'participant', `expected role=participant, got ${role}`);
});
it('grants member affiliation when moderator=false', async () => {
const r = nextRoom();
clients.push(await joinWithFocus(r));
const c = await connectWithToken(r, { moderator: false });
clients.push(c);
const { affiliation } = getRoleAndAffiliation(await c.joinRoom(r));
assert.equal(affiliation, 'member');
});
// -------------------------------------------------------------------------
// No token (anonymous)
// -------------------------------------------------------------------------
it('leaves affiliation unchanged for anonymous user (no token)', async () => {
const r = nextRoom();
clients.push(await joinWithFocus(r));
const c = await createXmppClient();
clients.push(c);
const presence = await c.joinRoom(r);
const { role, affiliation } = getRoleAndAffiliation(presence);
// No token → token_affiliation is a no-op; Prosody default is none/participant.
assert.equal(affiliation, 'none', `expected affiliation=none, got ${affiliation}`);
assert.equal(role, 'participant', `expected role=participant, got ${role}`);
});
// -------------------------------------------------------------------------
// Multiple participants in the same room
// -------------------------------------------------------------------------
it('correctly assigns different roles to moderator and non-moderator in same room', async () => {
const r = nextRoom();
clients.push(await joinWithFocus(r));
const mod = await connectWithToken(r, { moderator: true });
const member = await connectWithToken(r, { id: 'plain' });
clients.push(mod, member);
const modPresence = await mod.joinRoom(r);
const memberPresence = await member.joinRoom(r);
assert.equal(getRoleAndAffiliation(modPresence).role, 'moderator');
assert.equal(getRoleAndAffiliation(modPresence).affiliation, 'owner');
assert.equal(getRoleAndAffiliation(memberPresence).role, 'participant');
assert.equal(getRoleAndAffiliation(memberPresence).affiliation, 'member');
});
});