Skip to content

Commit 19bb5fc

Browse files
committed
test(security): add security verification suite
1 parent e577793 commit 19bb5fc

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

learnmate-backend/test-security.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
const axios = require('axios');
2+
3+
const BASE_URL = 'http://localhost:5000/api';
4+
const AUTH_URL = `${BASE_URL}/auth`;
5+
const GAMIFICATION_URL = `${BASE_URL}/gamification`;
6+
7+
// Helper for delays
8+
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
9+
10+
async function runSecurityTests() {
11+
console.log('🛡️ STARTING "BREAK-IT" SECURITY SUITE 🛡️');
12+
let email = `attacker_${Date.now()}@test.com`;
13+
let token = '';
14+
15+
// 1. Setup: Create User
16+
try {
17+
console.log('\n[SETUP] Creating Attacker Account...');
18+
const res = await axios.post(`${AUTH_URL}/register`, {
19+
name: 'Attacker', email, password: 'password123', semester: 1
20+
});
21+
token = res.data.data.token;
22+
console.log('✅ Account Created');
23+
} catch (e) {
24+
console.error('❌ Setup Failed:', e.message);
25+
return;
26+
}
27+
28+
// 2. Test Rate Limiting (DoS)
29+
console.log('\n[TEST 1] Rate Limiting (DoS Attempt on /me)...');
30+
try {
31+
let blocked = false;
32+
// API Limit is 300, so we need to hit it hard or hit the Auth limit (5)
33+
// Let's hit Auth limit on /login which is 5/15min
34+
for (let i = 0; i < 10; i++) {
35+
try {
36+
process.stdout.write(`\rRequest ${i + 1}/10...`);
37+
await axios.post(`${AUTH_URL}/login`, { email, password: 'wrongpassword' });
38+
} catch (e) {
39+
if (e.response && e.response.status === 429) {
40+
blocked = true;
41+
console.log('\n✅ Rate Limit Triggered! (429 Too Many Requests)');
42+
break;
43+
}
44+
}
45+
}
46+
if (!blocked) console.log('\n❌ Rate Limit NOT Triggered (Check configuration)');
47+
} catch (e) {
48+
console.error('Test Error:', e.message);
49+
}
50+
51+
// 3. Test Negative Number Exploit (Gamification)
52+
console.log('\n[TEST 2] Negative Number Exploit (Infinite Money Glitch)...');
53+
try {
54+
await axios.post(`${GAMIFICATION_URL}/purchase`, {
55+
itemId: 'exploit_item',
56+
type: 'feature',
57+
cost: { coins: -10000 } // Should be rejected
58+
}, { headers: { Authorization: `Bearer ${token}` } });
59+
console.error('❌ FAILED: Server accepted negative cost!');
60+
} catch (e) {
61+
if (e.response && e.response.data.errors) {
62+
const errs = JSON.stringify(e.response.data.errors);
63+
if (errs.includes('must be positive')) {
64+
console.log(`✅ Server Correctly Rejected Payload: ${errs}`);
65+
} else {
66+
console.log(`⚠️ Rejected but unexpected error: ${errs}`);
67+
}
68+
} else {
69+
console.log(`✅ Request Failed (Good): ${e.response?.status}`);
70+
}
71+
}
72+
73+
// 4. Test Payload Size (AI DoS)
74+
console.log('\n[TEST 3] Massive Payload Attack (AI Service)...');
75+
try {
76+
const massivePayload = {
77+
userId: "attacker",
78+
performance: { "math": "A" },
79+
semester: 1,
80+
extraData: "A".repeat(1024 * 1024) // 1MB String
81+
};
82+
// This hits the node proxy first, then python. Node doesn't validate size explicitly but Python does.
83+
// Actually, Express body-parser might limit it (default 100kb).
84+
await axios.post(`${BASE_URL}/onboarding/complete`, massivePayload, {
85+
headers: { Authorization: `Bearer ${token}` }
86+
});
87+
console.error('❌ Server accepted 1MB payload (Check body-parser limit)');
88+
} catch (e) {
89+
if (e.response && e.response.status === 413) {
90+
console.log('✅ Payload Too Large (413) - Express Blocked it');
91+
} else if (e.response && e.response.status === 500) {
92+
console.log('⚠️ Server Error (500) - Likely Python side rejected or timed out');
93+
} else {
94+
console.log(`✅ Request Failed: ${e.response?.status} - ${e.message}`);
95+
}
96+
}
97+
98+
console.log('\n--- 🏁 SECURITY SUITE COMPLETE 🏁 ---');
99+
}
100+
101+
runSecurityTests();

0 commit comments

Comments
 (0)