Skip to content

Commit 7635a21

Browse files
authored
General maintenance (VandyHacks#518)
* Add helmet for express * Optimize webpack/ts builds a bit * Disable cors, use secure cookies * Turn off introspection, fix server bug * Revert webpack changes * Fix lint
1 parent 60eb4f5 commit 7635a21

File tree

6 files changed

+178
-45
lines changed

6 files changed

+178
-45
lines changed

.env.template

-3
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ MONGODB_BASE_URL=localhost:27017
77
# server port
88
PORT=8080
99

10-
# for CORS, should start with a '.' (eg. ".vandyhacks.org")
11-
PROD_ORIGIN='production_url'
12-
1310
# for encrypting server sessions
1411
SESSION_SECRET=test
1512

package-lock.json

+139
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"googleapis": "^44.0.0",
9797
"graphql": "^14.5.8",
9898
"graphql-tag": "^2.10.1",
99+
"helmet": "^3.21.2",
99100
"immer": "^4.0.2",
100101
"jest-junit": "^9.0.0",
101102
"mongodb": "^3.3.3",
@@ -140,6 +141,7 @@
140141
"@types/express": "^4.17.1",
141142
"@types/express-session": "^1.15.15",
142143
"@types/faker": "^4.1.6",
144+
"@types/helmet": "0.0.45",
143145
"@types/jest": "^24.0.20",
144146
"@types/mongodb": "^3.3.6",
145147
"@types/node": "^12.11.7",

src/server/index.ts

+14-30
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { DIRECTIVES } from '@graphql-codegen/typescript-mongodb';
33
import express from 'express';
44
import passport from 'passport';
55
import session from 'express-session';
6-
import cors, { CorsOptions } from 'cors';
6+
import helmet from 'helmet';
77
import MongoStore, { MongoUrlOptions } from 'connect-mongo';
88
import gqlSchema from '../common/schema.graphql';
99
import { resolvers } from './resolvers';
@@ -15,11 +15,10 @@ import { UnsubscribeHandler } from './mail/handlers';
1515
import { UserDbInterface } from './generated/graphql';
1616
import { pullCalendar } from './events';
1717

18-
const { SESSION_SECRET, PORT, CALENDARID, NODE_ENV, PROD_ORIGIN } = process.env;
18+
const { SESSION_SECRET, PORT, CALENDARID, NODE_ENV } = process.env;
1919
if (!SESSION_SECRET) throw new Error(`SESSION_SECRET not set`);
2020
if (!PORT) throw new Error(`PORT not set`);
2121
if (!CALENDARID) logger.info('CALENDARID not set; skipping ical integration');
22-
if (!PROD_ORIGIN) throw new Error(`PROD_ORIGIN not set`);
2322
const IS_PROD = NODE_ENV === 'production';
2423
logger.info(`Node env: ${NODE_ENV}`);
2524

@@ -38,8 +37,7 @@ export const schema = makeExecutableSchema({
3837
const dbClient = new DB();
3938
const models = await dbClient.collections;
4039

41-
// Email unsubscribe link
42-
app.use('/api/unsubscribe', UnsubscribeHandler(models));
40+
app.use(helmet()); // sets good security defaults, see https://helmetjs.github.io/
4341

4442
// Register auth functions
4543
app.use(
@@ -48,6 +46,7 @@ export const schema = makeExecutableSchema({
4846
store: new (MongoStore(session))(({
4947
clientPromise: dbClient.client,
5048
} as unknown) as MongoUrlOptions),
49+
cookie: { secure: true },
5150
})
5251
);
5352
app.use(passport.initialize());
@@ -66,6 +65,9 @@ export const schema = makeExecutableSchema({
6665
})(req, res, next)
6766
);
6867

68+
// Email unsubscribe link
69+
app.use('/api/unsubscribe', UnsubscribeHandler(models));
70+
6971
// Pull events callback
7072
app.use('/api/manage/events/pull', async (req, res) => {
7173
const calendar = await pullCalendar(CALENDARID);
@@ -82,43 +84,25 @@ export const schema = makeExecutableSchema({
8284
// give friendly error message to frontend, hide internal server details
8385
return new Error(error.message);
8486
},
85-
introspection: true, // OFF by default in prod, needs to be set true to remove compile errors
87+
introspection: false, // OFF by default in prod for security reasons
8688
// playground: NODE_ENV !== 'production', // by DEFAULT, enabled when not in prod + disabled in prod
8789
schema,
8890
});
8991

90-
const allowedOrigin = IS_PROD ? PROD_ORIGIN || '' : '';
91-
logger.info(`Allowed origins: ${allowedOrigin}`);
92-
93-
const corsOptions: CorsOptions = {
94-
origin(requestOrigin, cb) {
95-
if (requestOrigin === null || requestOrigin === undefined) {
96-
logger.error('Request origin missing, not allowed by CORS');
97-
return;
98-
}
99-
const allowed = !IS_PROD || requestOrigin.endsWith(allowedOrigin);
100-
101-
logger.info(requestOrigin, allowed);
102-
if (!allowed) {
103-
logger.error('Not allowed by CORS');
104-
return;
105-
}
106-
cb(null, allowed);
107-
},
108-
};
109-
110-
server.applyMiddleware({ app, cors: corsOptions });
92+
server.applyMiddleware({ app });
11193

112-
if (IS_PROD) {
94+
if (NODE_ENV !== 'development') {
11395
// Serve front-end asset files in prod.
11496
app.use(express.static('dist/server/app'));
11597
// MUST BE LAST AS THIS WILL REROUTE ALL REMAINING TRAFFIC TO THE FRONTEND!
116-
app.use((req, res) => res.sendFile('index.html', { root: 'dist/server/app' }));
98+
app.use((req, res) => {
99+
res.sendFile('index.html', { root: 'dist/server/app' });
100+
});
117101
}
118102

119103
app.listen(
120104
{ port: PORT },
121-
() => void logger.info(`Server ready at http://localhost:8080${server.graphqlPath}`)
105+
() => void logger.info(`Server ready at http://localhost:${PORT}${server.graphqlPath}`)
122106
);
123107
})();
124108

tsconfig.json

+15-4
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,20 @@
1616
"outDir": "./dist/",
1717
"baseUrl": ".",
1818
"paths": {
19-
"*": ["node_modules/*", "types/*"]
19+
"*": [
20+
"node_modules/*",
21+
"types/*"
22+
]
2023
}
2124
},
22-
"include": ["src/**/*"],
23-
"exclude": ["types/*"]
24-
}
25+
"include": [
26+
"src/**/*.ts",
27+
"src/client/**/*.tsx"
28+
],
29+
"exclude": [
30+
"node_modules/**",
31+
"types/**",
32+
"src/**/*.test.ts",
33+
"src/client/**/*.test.tsx"
34+
]
35+
}

0 commit comments

Comments
 (0)