55 lines
2.4 KiB
TypeScript
55 lines
2.4 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { ApiServer } from './src/services/apiServer.js';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
const repoRoot = __dirname;
|
|
|
|
async function verifyStaticGuards(): Promise<void> {
|
|
const apiServerSource = fs.readFileSync(path.join(repoRoot, 'src/services/apiServer.ts'), 'utf8');
|
|
const supabaseSource = fs.readFileSync(path.join(repoRoot, 'src/services/SupabaseService.ts'), 'utf8');
|
|
|
|
assert(/app\.post\('\/api\/trade',\s*this\.requireAuth/.test(apiServerSource), 'Missing auth guard on /api/trade');
|
|
assert(/app\.post\('\/api\/close',\s*this\.requireAuth/.test(apiServerSource), 'Missing auth guard on /api/close');
|
|
assert(/app\.post\('\/api\/chat',\s*this\.requireAuth/.test(apiServerSource), 'Missing auth guard on /api/chat');
|
|
assert(/this\.io\.use\(async\s*\(socket,\s*next\)/.test(apiServerSource), 'Missing websocket auth middleware');
|
|
assert(/Unauthorized:\s*missing token/.test(apiServerSource), 'Missing explicit websocket unauthorized path');
|
|
assert(/SUPABASE_JWT_ISSUER/.test(supabaseSource), 'Missing JWT issuer check wiring');
|
|
assert(/SUPABASE_JWT_AUDIENCE/.test(supabaseSource), 'Missing JWT audience check wiring');
|
|
assert(/Invalid token issuer/.test(supabaseSource), 'Missing explicit invalid issuer rejection');
|
|
assert(/Invalid token audience/.test(supabaseSource), 'Missing explicit invalid audience rejection');
|
|
}
|
|
|
|
async function verifyRuntimeGuards(): Promise<void> {
|
|
const port = 5900 + Math.floor(Math.random() * 300);
|
|
const server = new ApiServer(port);
|
|
|
|
try {
|
|
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
|
|
const response = await fetch(`http://127.0.0.1:${port}/api/trade`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
symbol: 'BTC/USD',
|
|
side: 'buy',
|
|
qty: 0.01,
|
|
type: 'market'
|
|
})
|
|
});
|
|
|
|
assert.equal(response.status, 401, `Expected 401 for unauthorized /api/trade, got ${response.status}`);
|
|
} finally {
|
|
await server.stop();
|
|
}
|
|
}
|
|
|
|
await verifyStaticGuards();
|
|
await verifyRuntimeGuards();
|
|
console.log('[security-guards] OK: static + unauthorized REST checks passed');
|