Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,27 @@ services:
image: postgres:15
environment:
POSTGRES_DB: tradeflow

```

## 🔒 Security & CORS

The API is configured with strict Cross-Origin Resource Sharing (CORS) policies to ensure secure communication:

- **Allowed Origins**:
- `http://localhost:3000` (Local Development)
- `https://tradeflow-web.vercel.app` (Production)
- **Allowed Methods**: `GET`, `POST`, `PUT`, `PATCH`

### Verifying CORS
To verify the CORS configuration, ensure dependencies are installed and the server is running, then execute the test script:

```bash
# 1. Install dependencies
npm install

# 2. Start the server
npm run start

# 3. Run the CORS verification script (in a new terminal)
node test-cors.js
```
10 changes: 9 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,15 @@ import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors(); // Vital for Frontend connection
// Configure CORS for secure cross-origin communication
app.enableCors({
origin: [
'http://localhost:3000', // Local development environment
'https://tradeflow-web.vercel.app', // Production environment
],
methods: ['GET', 'POST', 'PUT', 'PATCH'],
credentials: true,
});

const config = new DocumentBuilder()
.setTitle('TradeFlow API')
Expand Down
63 changes: 63 additions & 0 deletions test-cors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const http = require('http');

const options = {
hostname: 'localhost',
port: 3000,
path: '/health',
method: 'GET',
headers: {
'Origin': 'http://localhost:3000'
}
};

function checkCors(origin, expectedStatus, expectedAllowOrigin) {
return new Promise((resolve, reject) => {
const reqOptions = { ...options, headers: { 'Origin': origin } };
const req = http.request(reqOptions, (res) => {
const allowOrigin = res.headers['access-control-allow-origin'];
console.log(`Origin: ${origin}, Status: ${res.statusCode}, Access-Control-Allow-Origin: ${allowOrigin}`);

if (expectedAllowOrigin) {
if (allowOrigin === expectedAllowOrigin) {
resolve(true);
} else {
reject(new Error(`Expected ${expectedAllowOrigin}, got ${allowOrigin}`));
}
} else {
if (!allowOrigin) {
resolve(true);
} else {
reject(new Error(`Expected no Access-Control-Allow-Origin, got ${allowOrigin}`));
}
}
});

req.on('error', (e) => {
reject(e);
});

req.end();
});
}

async function runTests() {
try {
console.log('Testing Allowed Origin 1: http://localhost:3000');
await checkCors('http://localhost:3000', 200, 'http://localhost:3000');

console.log('Testing Allowed Origin 2: https://tradeflow-web.vercel.app');
await checkCors('https://tradeflow-web.vercel.app', 200, 'https://tradeflow-web.vercel.app');

console.log('Testing Disallowed Origin: http://evil.com');
await checkCors('http://evil.com', 200, undefined); // Should not return the header

console.log('All CORS tests passed!');
} catch (error) {
console.error('CORS Test Failed:', error.message);
process.exit(1);
}
}

// Give server a moment to start if needed, but this script assumes it's running.
// If run via a command that starts server then runs this, we need a wait.
runTests();