Skip to content

Commit bb5ed56

Browse files
committed
feat: cors done
1 parent 67be593 commit bb5ed56

11 files changed

Lines changed: 980 additions & 24 deletions

File tree

backend/.env.example

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,20 @@ STELLAR_NETWORK_PASSPHRASE=Test SDF Network ; September 2015
2222
# Vault Configuration
2323
VAULT_CONTRACT_ID=
2424

25-
# Optional: Database Configuration (for future use)
26-
# DATABASE_URL=
27-
# DATABASE_POOL_SIZE=10
25+
# Optional: Database Configuration
26+
DATABASE_URL=
27+
DATABASE_REPLICA_URL=
28+
DATABASE_POOL_SIZE=10
2829

2930
# Optional: Cache Configuration (for future use)
3031
# REDIS_URL=redis://localhost:6379
3132
# CACHE_TTL=300
33+
34+
# CORS Configuration
35+
# Comma-separated list of allowed origins. Supports strings or regex like /https?:\/\/.*\.yieldvault\.finance/
36+
CORS_ALLOWED_ORIGINS=http://localhost:3000,https://app.yieldvault.finance
37+
38+
# Email Notification Configuration
39+
EMAIL_PROVIDER=resend
40+
EMAIL_API_KEY=
41+
EMAIL_FROM_ADDRESS=notifications@yieldvault.finance

backend/package-lock.json

Lines changed: 77 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,27 @@
2121
"author": "",
2222
"license": "MIT",
2323
"dependencies": {
24+
"cors": "^2.8.6",
25+
"dotenv": "^16.3.1",
2426
"express": "^4.18.2",
2527
"express-rate-limit": "^7.0.0",
26-
"dotenv": "^16.3.1",
27-
"node-cache": "^5.1.2"
28+
"node-cache": "^5.1.2",
29+
"prom-client": "^15.1.3"
2830
},
2931
"devDependencies": {
32+
"@types/cors": "^2.8.19",
3033
"@types/express": "^4.17.17",
31-
"@types/node": "^20.0.0",
3234
"@types/jest": "^29.5.0",
33-
"typescript": "^5.1.0",
34-
"tsx": "^4.0.0",
35-
"jest": "^29.5.0",
36-
"ts-jest": "^29.1.0",
37-
"supertest": "^6.3.3",
35+
"@types/node": "^20.0.0",
3836
"@types/supertest": "^2.0.12",
39-
"eslint": "^8.40.0",
4037
"@typescript-eslint/eslint-plugin": "^5.59.0",
4138
"@typescript-eslint/parser": "^5.59.0",
42-
"prettier": "^3.0.0"
39+
"eslint": "^8.40.0",
40+
"jest": "^29.5.0",
41+
"prettier": "^3.0.0",
42+
"supertest": "^6.3.3",
43+
"ts-jest": "^29.1.0",
44+
"tsx": "^4.0.0",
45+
"typescript": "^5.1.0"
4346
}
4447
}

backend/src/__tests__/cors.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import request from 'supertest';
2+
import express, { Express } from 'express';
3+
import { corsMiddleware } from '../middleware/cors';
4+
5+
describe('CORS Middleware', () => {
6+
let app: Express;
7+
8+
beforeAll(() => {
9+
app = express();
10+
// Set a dummy environment origin for testing
11+
process.env.CORS_ALLOWED_ORIGINS = 'http://trusted-frontend.com,https://app.yieldvault.finance';
12+
process.env.NODE_ENV = 'production';
13+
14+
app.use(corsMiddleware);
15+
app.get('/test', (req, res) => {
16+
res.status(200).json({ message: 'Success' });
17+
});
18+
});
19+
20+
it('should allow requests from a trusted origin', async () => {
21+
const response = await request(app)
22+
.get('/test')
23+
.set('Origin', 'http://trusted-frontend.com');
24+
25+
expect(response.status).toBe(200);
26+
expect(response.header['access-control-allow-origin']).toBe('http://trusted-frontend.com');
27+
expect(response.header['access-control-allow-credentials']).toBe('true');
28+
});
29+
30+
it('should allow requests from another trusted origin', async () => {
31+
const response = await request(app)
32+
.get('/test')
33+
.set('Origin', 'https://app.yieldvault.finance');
34+
35+
expect(response.status).toBe(200);
36+
expect(response.header['access-control-allow-origin']).toBe('https://app.yieldvault.finance');
37+
});
38+
39+
it('should reject requests from an untrusted origin with 403', async () => {
40+
const response = await request(app)
41+
.get('/test')
42+
.set('Origin', 'http://malicious-site.com');
43+
44+
expect(response.status).toBe(403);
45+
expect(response.body).toHaveProperty('error', 'Forbidden');
46+
expect(response.body).toHaveProperty('message', 'CORS policy: This origin is not allowed access.');
47+
expect(response.header['access-control-allow-origin']).toBeUndefined();
48+
});
49+
50+
it('should allow requests with no origin (e.g., mobile apps, curl)', async () => {
51+
const response = await request(app).get('/test');
52+
53+
expect(response.status).toBe(200);
54+
expect(response.body).toHaveProperty('message', 'Success');
55+
});
56+
57+
it('should return correct headers for preflight OPTIONS requests from trusted origin', async () => {
58+
const response = await request(app)
59+
.options('/test')
60+
.set('Origin', 'http://trusted-frontend.com')
61+
.set('Access-Control-Request-Method', 'POST');
62+
63+
expect(response.status).toBe(200);
64+
expect(response.header['access-control-allow-origin']).toBe('http://trusted-frontend.com');
65+
expect(response.header['access-control-allow-methods']).toContain('POST');
66+
});
67+
68+
it('should reject preflight OPTIONS requests from untrusted origin with 403', async () => {
69+
const response = await request(app)
70+
.options('/test')
71+
.set('Origin', 'http://malicious-site.com')
72+
.set('Access-Control-Request-Method', 'POST');
73+
74+
expect(response.status).toBe(403);
75+
});
76+
});

0 commit comments

Comments
 (0)