|
|
/**
|
|
|
* Command logging and date‑handling tests.
|
|
|
*
|
|
|
* Covers tarea command logging, date parsing edge cases, XSS/SQL
|
|
|
* injection resilience, and sender ID normalization.
|
|
|
*/
|
|
|
import { describe, test, expect } from 'bun:test';
|
|
|
import { WebhookServer } from '../../src/server';
|
|
|
import { SimulatedResponseQueue } from '../helpers/queue';
|
|
|
import { createTestRequest, getFutureDate, registerServerTestLifecycle } from '../helpers/server-test-harness';
|
|
|
|
|
|
const testDb = registerServerTestLifecycle();
|
|
|
|
|
|
// ── Tests ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
describe('tarea command logging', () => {
|
|
|
test('should log basic tarea command', async () => {
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'user123@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: 'tarea test' },
|
|
|
},
|
|
|
};
|
|
|
|
|
|
await WebhookServer.handleRequest(createTestRequest(payload));
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
|
|
|
test('should log command with due date', async () => {
|
|
|
const futureDate = getFutureDate(3);
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'user123@s.whatsapp.net',
|
|
|
},
|
|
|
message: {
|
|
|
conversation: `tarea nueva Finish project @user2 ${futureDate}`,
|
|
|
contextInfo: {
|
|
|
mentionedJid: ['user2@s.whatsapp.net'],
|
|
|
},
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
|
|
|
await WebhookServer.handleRequest(createTestRequest(payload));
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
});
|
|
|
|
|
|
describe('WebhookServer — Date handling & edge cases', () => {
|
|
|
test('should handle XSS/SQL injection attempts', async () => {
|
|
|
const maliciousMessage = `tarea nueva <script>alert('xss')</script>'; DROP TABLE tasks; --`;
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'sender-id@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: maliciousMessage },
|
|
|
},
|
|
|
};
|
|
|
const request = createTestRequest(payload);
|
|
|
const response = await WebhookServer.handleRequest(request);
|
|
|
expect(response.status).toBe(200);
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
|
|
|
test('should handle multiple dates in command (use last one as due date)', async () => {
|
|
|
const futureDate1 = getFutureDate(3);
|
|
|
const futureDate2 = getFutureDate(5);
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'sender-id@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: `tarea nueva Test task ${futureDate1} some text ${futureDate2}` },
|
|
|
},
|
|
|
};
|
|
|
|
|
|
await WebhookServer.handleRequest(createTestRequest(payload));
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
|
|
|
test('should ignore past dates as due dates', async () => {
|
|
|
const pastDate = '2020-01-01';
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'sender-id@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: `tarea nueva Old task ${pastDate}` },
|
|
|
},
|
|
|
};
|
|
|
|
|
|
await WebhookServer.handleRequest(createTestRequest(payload));
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
|
|
|
test('should handle multiple past dates correctly', async () => {
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'sender-id@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: 'tarea nueva Test 2020-01-01 2020-02-01' },
|
|
|
},
|
|
|
};
|
|
|
|
|
|
await WebhookServer.handleRequest(createTestRequest(payload));
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
|
|
|
test('should handle mixed valid and invalid date formats', async () => {
|
|
|
const futureDate = getFutureDate(3);
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'sender-id@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: `tarea nueva Test invalid-date ${futureDate} another-bad` },
|
|
|
},
|
|
|
};
|
|
|
|
|
|
await WebhookServer.handleRequest(createTestRequest(payload));
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
|
|
|
test('should normalize sender ID before processing', async () => {
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'sender-id:12@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: 'tarea nueva Test' },
|
|
|
},
|
|
|
};
|
|
|
const request = createTestRequest(payload);
|
|
|
const response = await WebhookServer.handleRequest(request);
|
|
|
expect(response.status).toBe(200);
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
});
|
|
|
|
|
|
test('should ignore messages with invalid sender ID', async () => {
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'invalid!@#$',
|
|
|
},
|
|
|
message: { conversation: 'tarea nueva Test' },
|
|
|
},
|
|
|
};
|
|
|
const request = createTestRequest(payload);
|
|
|
const response = await WebhookServer.handleRequest(request);
|
|
|
expect(response.status).toBe(200);
|
|
|
expect(SimulatedResponseQueue.get().length).toBe(0);
|
|
|
});
|
|
|
|
|
|
test('should ensure user exists and use normalized ID', async () => {
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: '1234567890@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: 'tarea nueva Test user' },
|
|
|
},
|
|
|
};
|
|
|
const request = createTestRequest(payload);
|
|
|
const response = await WebhookServer.handleRequest(request);
|
|
|
expect(response.status).toBe(200);
|
|
|
expect(SimulatedResponseQueue.get().length).toBeGreaterThan(0);
|
|
|
|
|
|
const user = testDb.query('SELECT * FROM users WHERE id = ?').get('1234567890');
|
|
|
expect(user).toBeDefined();
|
|
|
expect((user as any).id).toBe('1234567890');
|
|
|
});
|
|
|
|
|
|
test('should ignore messages if user creation fails', async () => {
|
|
|
const payload = {
|
|
|
event: 'messages.upsert',
|
|
|
instance: 'test-instance',
|
|
|
data: {
|
|
|
key: {
|
|
|
remoteJid: 'group-id@g.us',
|
|
|
participant: 'invalid!user@s.whatsapp.net',
|
|
|
},
|
|
|
message: { conversation: 'tarea nueva Test' },
|
|
|
},
|
|
|
};
|
|
|
const request = createTestRequest(payload);
|
|
|
const response = await WebhookServer.handleRequest(request);
|
|
|
expect(response.status).toBe(200);
|
|
|
expect(SimulatedResponseQueue.get().length).toBe(0);
|
|
|
|
|
|
const userCount = testDb.query('SELECT COUNT(*) as count FROM users').get();
|
|
|
expect((userCount as any).count).toBe(0);
|
|
|
});
|
|
|
});
|