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.
166 lines
5.6 KiB
TypeScript
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);
|
|
});
|
|
|
|
});
|