Files
wehub-resource-sync 7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:55 +08:00

213 lines
8.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Rate Limiting Functionality Test
*
* Tests that rate limiting is working correctly on authentication endpoints.
* Verifies that requests are blocked after exceeding limits and that proper
* headers are returned.
*
* Prerequisites: Web server running on http://127.0.0.1:5000
*
* Usage: node tests/ui_tests/test_rate_limiting_settings.js
*/
const puppeteer = require('puppeteer');
const { getPuppeteerLaunchOptions } = require('./puppeteer_config');
async function testRateLimiting() {
// Skip this test in CI unless ENABLE_RATE_LIMITING=true
// Rate limiting is disabled in CI by default, so this test would fail
if (process.env.CI && process.env.ENABLE_RATE_LIMITING !== 'true') {
console.log('⚠️ Skipping rate limiting test in CI (requires ENABLE_RATE_LIMITING=true)');
console.log('️ This test needs rate limiting enabled, but CI disables it by default');
return; // Caller awaits but doesn't use return value
}
const browser = await puppeteer.launch(getPuppeteerLaunchOptions());
const page = await browser.newPage();
const baseUrl = 'http://127.0.0.1:5000';
try {
console.log('🚀 Starting rate limiting functionality test...');
// Test 1: Test login rate limiting (5 per 15 minutes)
console.log('\n🔍 Test 1: Login endpoint should be rate limited (5 attempts per 15 min)');
await page.goto(`${baseUrl}/auth/login`, { waitUntil: 'domcontentloaded' });
let loginAttempts = 0;
let rateLimitTriggered = false;
// Make login attempts until rate limited
for (let i = 0; i < 10; i++) {
const response = await page.evaluate(async (url) => {
const res = await fetch(`${url}/api/v1/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: 'testuser_nonexistent',
password: 'wrongpassword' // gitleaks:allow
})
});
return {
status: res.status,
headers: {
ratelimitLimit: res.headers.get('X-RateLimit-Limit'),
ratelimitRemaining: res.headers.get('X-RateLimit-Remaining'),
ratelimitReset: res.headers.get('X-RateLimit-Reset')
}
};
}, baseUrl);
loginAttempts++;
if (response.status === 429) {
console.log(`✅ Rate limit triggered after ${loginAttempts} login attempts`);
console.log(`📊 Rate limit headers:`, response.headers);
rateLimitTriggered = true;
break;
} else {
console.log(`📍 Login attempt ${loginAttempts}: status ${response.status}, remaining: ${response.headers.ratelimitRemaining}`);
}
// Small delay between requests
await new Promise(resolve => setTimeout(resolve, 100));
}
if (!rateLimitTriggered) {
console.log('❌ Rate limit was not triggered after 10 login attempts');
throw new Error('Login rate limiting is not working');
}
if (loginAttempts > 6) {
console.log(`⚠️ Rate limit triggered later than expected (after ${loginAttempts} attempts, expected ~5)`);
}
// Test 2: Test registration rate limiting (3 per hour)
console.log('\n🔍 Test 2: Registration endpoint should be rate limited (3 attempts per hour)');
// Use a different page context to reset cookies/session
const page2 = await browser.newPage();
await page2.goto(`${baseUrl}/auth/register`, { waitUntil: 'domcontentloaded' });
let registrationAttempts = 0;
let regRateLimitTriggered = false;
// Make registration attempts until rate limited
for (let i = 0; i < 10; i++) {
const response = await page2.evaluate(async (url, attemptNum) => {
const res = await fetch(`${url}/api/v1/auth/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: `testuser_ratelimit_${Date.now()}_${attemptNum}`,
password: 'testpassword123' // gitleaks:allow
})
});
return {
status: res.status,
headers: {
ratelimitLimit: res.headers.get('X-RateLimit-Limit'),
ratelimitRemaining: res.headers.get('X-RateLimit-Remaining'),
ratelimitReset: res.headers.get('X-RateLimit-Reset')
}
};
}, baseUrl, i);
registrationAttempts++;
if (response.status === 429) {
console.log(`✅ Rate limit triggered after ${registrationAttempts} registration attempts`);
console.log(`📊 Rate limit headers:`, response.headers);
regRateLimitTriggered = true;
break;
} else {
console.log(`📍 Registration attempt ${registrationAttempts}: status ${response.status}, remaining: ${response.headers.ratelimitRemaining}`);
}
// Small delay between requests
await new Promise(resolve => setTimeout(resolve, 100));
}
if (!regRateLimitTriggered) {
console.log('❌ Rate limit was not triggered after 10 registration attempts');
throw new Error('Registration rate limiting is not working');
}
if (registrationAttempts > 4) {
console.log(`⚠️ Rate limit triggered later than expected (after ${registrationAttempts} attempts, expected ~3)`);
}
await page2.close();
// Test 3: Verify 429 error response format
console.log('\n🔍 Test 3: Verify 429 error response format');
const errorResponse = await page.evaluate(async (url) => {
const res = await fetch(`${url}/api/v1/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: 'testuser',
password: 'testpass' // gitleaks:allow
})
});
const body = await res.json();
return {
status: res.status,
body
};
}, baseUrl);
if (errorResponse.status === 429) {
console.log('✅ 429 status code returned correctly');
console.log('📊 Error response body:', errorResponse.body);
if (errorResponse.body.error && errorResponse.body.message) {
console.log('✅ Error response has correct format (error and message fields)');
} else {
console.log('⚠️ Error response format unexpected:', errorResponse.body);
}
} else {
console.log(`️ Rate limit may have reset, got status ${errorResponse.status}`);
}
// Summary
console.log('\n📊 Test Summary:');
console.log(`✅ Login rate limiting (5 per 15 min): PASS (triggered after ${loginAttempts} attempts)`);
console.log(`✅ Registration rate limiting (3 per hour): PASS (triggered after ${registrationAttempts} attempts)`);
console.log(`✅ Error response format: PASS`);
console.log('\n🎉 Rate limiting functionality test completed successfully');
} catch (error) {
console.error('❌ Error during rate limiting test:', error);
throw error;
} finally {
await browser.close();
}
}
// Run the test
if (require.main === module) {
testRateLimiting()
.then(() => {
console.log('✅ All rate limiting tests completed');
process.exit(0);
})
.catch(error => {
console.error('❌ Rate limiting tests failed:', error);
process.exit(1);
});
}
module.exports = { testRateLimiting };