first commit
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { login, BASE_URL } from '../../helpers/auth';
|
||||
import { markPartial } from '../../helpers/manual';
|
||||
|
||||
test.describe('pbx-calls-security', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await login(page);
|
||||
});
|
||||
|
||||
test('pbx-calls-security-check-srtp_sdes_or_dtls_media_encryption', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({ type: 'automationStatus', description: 'partial' });
|
||||
testInfo.annotations.push({ type: 'testType', description: 'check' });
|
||||
markPartial('Encryption configuration can be verified via admin portal; confirming that live RTP traffic is actually encrypted requires packet capture (Wireshark) during an active call');
|
||||
testInfo.annotations.push({ type: 'description', description: 'Verify SRTP with SDES or DTLS-SRTP is enabled for media encryption on calls' });
|
||||
|
||||
await test.step('Navigate to Security → SIP / Media Encryption', async () => {
|
||||
await page.goto(`${BASE_URL}/admin/security/media-encryption`);
|
||||
});
|
||||
|
||||
await test.step('Verify media encryption settings page loads', async () => {
|
||||
await expect(page.locator('body')).not.toContainText(/500|not found/i);
|
||||
});
|
||||
|
||||
await test.step('Verify SRTP is enabled', async () => {
|
||||
const srtpToggle = page.locator('[name*="srtp"],[id*="srtp"],[data-field*="srtp"]').first();
|
||||
if (await srtpToggle.count() > 0) {
|
||||
await expect(srtpToggle).toBeChecked();
|
||||
} else {
|
||||
const pageText = await page.locator('body').textContent() ?? '';
|
||||
expect(pageText).toMatch(/srtp.*enabled|srtp.*on|media.*encrypt/i);
|
||||
}
|
||||
});
|
||||
|
||||
await test.step('Verify encryption mode is SDES or DTLS', async () => {
|
||||
const pageText = await page.locator('body').textContent() ?? '';
|
||||
expect(pageText).toMatch(/sdes|dtls/i);
|
||||
});
|
||||
|
||||
// TODO_MANUAL: While an active SRTP call is running, capture RTP packets with Wireshark.
|
||||
// Verify: no RTP packets are visible in plain text (audio payload is encrypted).
|
||||
// Confirm SDP shows a=crypto (SDES) or a=fingerprint (DTLS) attribute in INVITE/200 OK.
|
||||
});
|
||||
|
||||
test('pbx-calls-security-check-acl_ip_whitelisting_and_rate_limiting', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({ type: 'automationStatus', description: 'partial' });
|
||||
testInfo.annotations.push({ type: 'testType', description: 'check' });
|
||||
markPartial('ACL rule configuration can be verified via admin portal; testing that the rules actually block traffic requires attempting connections from non-whitelisted IPs — a network-level functional test');
|
||||
testInfo.annotations.push({ type: 'description', description: 'Verify ACL IP whitelisting rules and SIP rate limiting are configured and enforced' });
|
||||
|
||||
await test.step('Navigate to Security → ACL / Firewall', async () => {
|
||||
await page.goto(`${BASE_URL}/admin/security/acl`);
|
||||
});
|
||||
|
||||
await test.step('Verify ACL page loads', async () => {
|
||||
await expect(page.locator('body')).not.toContainText(/500|not found/i);
|
||||
});
|
||||
|
||||
await test.step('Verify at least one IP whitelist rule exists', async () => {
|
||||
const rules = page.locator('tr, .acl-entry').filter({ hasText: /allow|whitelist|permit/i });
|
||||
await expect(rules.first()).toBeVisible();
|
||||
});
|
||||
|
||||
await test.step('Navigate to rate limiting settings', async () => {
|
||||
await page.goto(`${BASE_URL}/admin/security/rate-limiting`);
|
||||
});
|
||||
|
||||
await test.step('Verify rate limit configuration is shown', async () => {
|
||||
await expect(page.locator('[name*="rate"],[id*="rate"],[class*="rate-limit"]').first()).toBeVisible();
|
||||
});
|
||||
|
||||
// TODO_MANUAL: From a non-whitelisted IP address, attempt a SIP REGISTER.
|
||||
// Verify the attempt is rejected (403 Forbidden or no response).
|
||||
// Send > rate-limit threshold requests/sec; verify subsequent requests are blocked.
|
||||
});
|
||||
|
||||
test('pbx-calls-security-check-toll_fraud_prevention_rules_and_alerting', async ({ page }, testInfo) => {
|
||||
testInfo.annotations.push({ type: 'automationStatus', description: 'automated' });
|
||||
testInfo.annotations.push({ type: 'testType', description: 'check' });
|
||||
testInfo.annotations.push({ type: 'description', description: 'Verify toll fraud prevention rules are configured and alert notifications are enabled' });
|
||||
|
||||
await test.step('Navigate to Security → Toll Fraud Prevention', async () => {
|
||||
await page.goto(`${BASE_URL}/admin/security/toll-fraud`);
|
||||
});
|
||||
|
||||
await test.step('Verify toll fraud page loads', async () => {
|
||||
await expect(page.locator('body')).not.toContainText(/500|not found/i);
|
||||
});
|
||||
|
||||
await test.step('Verify call limit thresholds are configured', async () => {
|
||||
const limitField = page.locator('[name*="max_calls"],[name*="call_limit"],[id*="threshold"]').first();
|
||||
if (await limitField.count() > 0) {
|
||||
const value = await limitField.inputValue();
|
||||
expect(parseInt(value, 10)).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
await test.step('Verify alerting email is configured', async () => {
|
||||
const emailField = page.locator('[name*="alert_email"],[name*="notification_email"]').first();
|
||||
if (await emailField.count() > 0) {
|
||||
const value = await emailField.inputValue();
|
||||
expect(value).toMatch(/@/);
|
||||
}
|
||||
});
|
||||
|
||||
await test.step('Verify geographic restrictions or blocked country codes are visible', async () => {
|
||||
const geoSection = page.locator('.geo-restriction, .country-block, [data-section="geo"]').first();
|
||||
if (await geoSection.count() > 0) {
|
||||
await expect(geoSection).toBeVisible();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user