You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
taskbot/tests/unit/server.dm-gating-regression...

166 lines
5.6 KiB
TypeScript

/**
* Regression tests: DM (direct message) gating.
*
* Ensures that user DMs are NEVER treated as groups for gating purposes.
* A user JID (e.g. 1234567890@s.whatsapp.net) must not trigger group
* discovery (notify admins of a "new group") or group enforcement
* (silently block the message).
*/
import { describe, test, expect } from 'bun:test';
import { WebhookServer } from '../../src/server';
import { SimulatedResponseQueue } from '../helpers/queue';
import { createTestRequest, registerServerTestLifecycle } from '../helpers/server-test-harness';
const testDb = registerServerTestLifecycle();
// ── Helpers ────────────────────────────────────────────────────────────
function makeDmPayload(text: string) {
return {
event: 'messages.upsert',
instance: 'test-instance',
data: {
key: {
remoteJid: '1234567890@s.whatsapp.net', // user JID, NOT a group
fromMe: false,
},
message: { conversation: text },
},
};
}
function countAllowedGroups(): number {
try {
const row = testDb.prepare('SELECT COUNT(*) AS c FROM allowed_groups').get() as { c: number };
return row.c;
} catch {
return 0;
}
}
// ── Tests ──────────────────────────────────────────────────────────────
describe('DM gating — user DMs must not be treated as groups', () => {
test('discover mode: DM does NOT register user JID in allowed_groups', async () => {
process.env.GROUP_GATING_MODE = 'discover';
const request = createTestRequest(makeDmPayload('t ver mis'));
const response = await WebhookServer.handleRequest(request);
expect(response.status).toBe(200);
// No allowed_groups entry should exist for the user JID
const count = countAllowedGroups();
expect(count).toBe(0);
// Admin should NOT be notified about a "new group"
const out = SimulatedResponseQueue.get();
const adminNotices = out.filter(r => r.message && (r.message as string).includes('Nuevo grupo detectado'));
expect(adminNotices.length).toBe(0);
});
test('enforce mode: DM is NOT blocked (user can still use commands)', async () => {
process.env.GROUP_GATING_MODE = 'enforce';
const request = createTestRequest(makeDmPayload('t ver mis'));
const response = await WebhookServer.handleRequest(request);
expect(response.status).toBe(200);
// Command should have processed and produced a response
const out = SimulatedResponseQueue.get();
// "ver mis" in DM should produce at least one response
expect(out.length).toBeGreaterThan(0);
});
test('discover mode: unknown GROUP still gets discovered (regression check)', async () => {
process.env.GROUP_GATING_MODE = 'discover';
process.env.NOTIFY_ADMINS_ON_DISCOVERY = 'false'; // don't spam admins in test
// Ensure the group is NOT already in allowed_groups or active groups
testDb.exec('DELETE FROM allowed_groups WHERE group_id = \'unknown-group@g.us\'');
testDb.exec('DELETE FROM groups WHERE id = \'unknown-group@g.us\'');
const payload = {
event: 'messages.upsert',
instance: 'test-instance',
data: {
key: {
remoteJid: 'unknown-group@g.us', // group JID
participant: '1234567890@s.whatsapp.net',
},
message: { conversation: 'hola' },
},
};
const request = createTestRequest(payload);
await WebhookServer.handleRequest(request);
// Should have registered the group as pending
const row = testDb.prepare('SELECT * FROM allowed_groups WHERE group_id = ?').get('unknown-group@g.us') as any;
expect(row).toBeDefined();
expect(row.status).toBe('pending');
});
test('enforce mode: non-allowed GROUP is still blocked (regression check)', async () => {
process.env.GROUP_GATING_MODE = 'enforce';
// Ensure the group is NOT allowed
testDb.exec('DELETE FROM allowed_groups WHERE group_id = \'blocked-group@g.us\'');
testDb.exec('DELETE FROM groups WHERE id = \'blocked-group@g.us\'');
// Add it as active so it passes ensureGroupActive
testDb.exec(`
INSERT OR IGNORE INTO groups (id, community_id, name, active)
VALUES ('blocked-group@g.us', 'test-community', 'Blocked Group', 1)
`);
const payload = {
event: 'messages.upsert',
instance: 'test-instance',
data: {
key: {
remoteJid: 'blocked-group@g.us',
participant: '1234567890@s.whatsapp.net',
},
message: { conversation: 't ver mis' },
},
};
const request = createTestRequest(payload);
await WebhookServer.handleRequest(request);
// Message should be silently blocked (no response)
const out = SimulatedResponseQueue.get();
expect(out.length).toBe(0);
});
test('enforce mode: allowed GROUP can still use commands (regression check)', async () => {
process.env.GROUP_GATING_MODE = 'enforce';
testDb.exec(`
INSERT OR REPLACE INTO allowed_groups (group_id, label, status)
VALUES ('group-id@g.us', 'Test Group', 'allowed')
`);
const payload = {
event: 'messages.upsert',
instance: 'test-instance',
data: {
key: {
remoteJid: 'group-id@g.us',
participant: '1234567890@s.whatsapp.net',
},
message: { conversation: 't n Test tarea mañana' },
},
};
const request = createTestRequest(payload);
await WebhookServer.handleRequest(request);
const out = SimulatedResponseQueue.get();
expect(out.length).toBeGreaterThan(0);
});
});