Skip to content

Commit c0a260c

Browse files
committed
feat(security): implement configurable CORS allowed origins
1 parent 641be28 commit c0a260c

File tree

2 files changed

+75
-61
lines changed

2 files changed

+75
-61
lines changed

src/config/index.ts

Lines changed: 38 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
11
export const config = {
2-
redis: {
3-
use: process.env.USE_REDIS === "true",
4-
uri: process.env.REDIS_URI,
5-
},
6-
env: process.env.NODE_ENV,
7-
adminApiKey: process.env.ADMIN_API_KEY,
8-
postgres: {
9-
username: process.env.POSTGRES_USER,
10-
password: process.env.POSTGRES_PASSWORD,
11-
database: process.env.POSTGRES_DB,
12-
host: process.env.POSTGRES_HOST ?? "localhost",
13-
port: process.env.POSTGRES_PORT ? Number(process.env.POSTGRES_PORT) : 5432,
14-
},
15-
ranking: {
16-
enabled: process.env.RANK_ENABLED === "true",
17-
},
18-
season: Number(process.env.SEASON),
19-
rateLimit: {
20-
enabled: process.env.RATE_LIMIT_ENABLED === "true",
21-
limit: Number(process.env.RATE_LIMIT),
22-
window: Number(process.env.RATE_LIMIT_WINDOW),
23-
},
24-
servers: {
25-
host: {
26-
port: Number(process.env.HOST_PORT),
27-
},
28-
mercury: {
29-
port: Number(process.env.MERCURY_PORT),
30-
},
31-
http: {
32-
port: Number(process.env.HTTP_PORT),
33-
},
34-
websocket: {
35-
port: Number(process.env.WEBSOCKET_PORT),
36-
duelPort: Number(process.env.WEBSOCKET_DUEL_PORT) || 4001,
37-
},
38-
},
2+
redis: {
3+
use: process.env.USE_REDIS === "true",
4+
uri: process.env.REDIS_URI,
5+
},
6+
env: process.env.NODE_ENV,
7+
adminApiKey: process.env.ADMIN_API_KEY,
8+
postgres: {
9+
username: process.env.POSTGRES_USER,
10+
password: process.env.POSTGRES_PASSWORD,
11+
database: process.env.POSTGRES_DB,
12+
host: process.env.POSTGRES_HOST ?? "localhost",
13+
port: process.env.POSTGRES_PORT ? Number(process.env.POSTGRES_PORT) : 5432,
14+
},
15+
ranking: {
16+
enabled: process.env.RANK_ENABLED === "true",
17+
},
18+
season: Number(process.env.SEASON),
19+
allowedOrigins: process.env.ALLOWED_ORIGINS?.split(",") ?? ["*"],
20+
rateLimit: {
21+
enabled: process.env.RATE_LIMIT_ENABLED === "true",
22+
limit: Number(process.env.RATE_LIMIT),
23+
window: Number(process.env.RATE_LIMIT_WINDOW),
24+
},
25+
servers: {
26+
host: {
27+
port: Number(process.env.HOST_PORT),
28+
},
29+
mercury: {
30+
port: Number(process.env.MERCURY_PORT),
31+
},
32+
http: {
33+
port: Number(process.env.HTTP_PORT),
34+
},
35+
websocket: {
36+
port: Number(process.env.WEBSOCKET_PORT),
37+
duelPort: Number(process.env.WEBSOCKET_DUEL_PORT) || 4001,
38+
},
39+
},
3940
};

src/http-server/Server.ts

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,43 @@ import { createDirectoryIfNotExists } from "../utils";
66
import { loadRoutes } from "./routes";
77

88
export class Server {
9-
private readonly app: Express;
10-
private readonly logger: Logger;
9+
private readonly app: Express;
10+
private readonly logger: Logger;
1111

12-
constructor(logger: Logger) {
13-
this.logger = logger;
14-
this.app = express();
15-
this.app.use(express.json());
16-
this.app.use((req, res, next) => {
17-
res.header("Access-Control-Allow-Origin", "*");
18-
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
19-
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
20-
if (req.method === "OPTIONS") {
21-
res.sendStatus(200);
22-
} else {
23-
next();
24-
}
25-
});
26-
loadRoutes(this.app, this.logger);
27-
}
12+
constructor(logger: Logger) {
13+
this.logger = logger;
14+
this.app = express();
15+
this.app.use(express.json());
16+
this.app.use((req, res, next) => {
17+
const origin = req.headers.origin;
18+
if (
19+
origin &&
20+
(config.allowedOrigins.includes("*") ||
21+
config.allowedOrigins.includes(origin))
22+
) {
23+
res.header("Access-Control-Allow-Origin", origin);
24+
}
25+
res.header(
26+
"Access-Control-Allow-Methods",
27+
"GET, POST, OPTIONS, PUT, DELETE",
28+
);
29+
res.header(
30+
"Access-Control-Allow-Headers",
31+
"Origin, X-Requested-With, Content-Type, Accept, Authorization, admin-api-key",
32+
);
33+
if (req.method === "OPTIONS") {
34+
res.sendStatus(200);
35+
} else {
36+
next();
37+
}
38+
});
39+
loadRoutes(this.app, this.logger);
40+
}
2841

29-
async initialize(): Promise<void> {
30-
await createDirectoryIfNotExists("./config");
31-
this.app.listen(config.servers.http.port, () => {
32-
this.logger.info(`Server listen in port ${config.servers.http.port}`);
33-
});
34-
}
42+
async initialize(): Promise<void> {
43+
await createDirectoryIfNotExists("./config");
44+
this.app.listen(config.servers.http.port, () => {
45+
this.logger.info(`Server listen in port ${config.servers.http.port}`);
46+
});
47+
}
3548
}

0 commit comments

Comments
 (0)