UNPKG

9.52 kBJavaScriptView Raw
1/*! edge-express v1.0.0-alpha.3 by Sebastian Software <s.werner@sebastian-software.de> */
2'use strict';
3
4Object.defineProperty(exports, '__esModule', { value: true });
5
6function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
7
8var compression = _interopDefault(require('compression'));
9var createLocaleMiddleware = _interopDefault(require('express-locale'));
10var cookieParser = _interopDefault(require('cookie-parser'));
11var bodyParser = _interopDefault(require('body-parser'));
12var PrettyError = _interopDefault(require('pretty-error'));
13var helmet = _interopDefault(require('helmet'));
14var parameterProtection = _interopDefault(require('hpp'));
15var uuid = _interopDefault(require('uuid'));
16var express = _interopDefault(require('express'));
17var dotenv = _interopDefault(require('dotenv'));
18
19function addCoreMiddleware(server, _ref) {
20 var locale = _ref.locale;
21
22 // Parse cookies via standard express tooling
23 server.use(cookieParser());
24
25 // Detect client locale and match it with configuration
26 server.use(createLocaleMiddleware({
27 priority: ["query", "cookie", "accept-language", "default"],
28 "default": locale["default"].replace(/-/, "_"),
29 allowed: locale.supported.map(function (entry) {
30 return entry.replace(/-/, "_");
31 })
32 }));
33
34 // Parse application/x-www-form-urlencoded
35 server.use(bodyParser.urlencoded({ extended: false }));
36
37 // Parse application/json
38 server.use(bodyParser.json());
39
40 // Compress output stream
41 server.use(compression());
42}
43
44var pretty = new PrettyError();
45
46// this will skip events.js and http.js and similar core node files
47pretty.skipNodeFiles();
48
49// this will skip all the trace lines about express` core and sub-modules
50pretty.skipPackage("express");
51
52function addErrorMiddleware(server) {
53 // and use it for our app's error handler:
54 server.use(function (error, request, response, next) {
55 // eslint-disable-line max-params
56 console.log(pretty.render(error));
57 next();
58 });
59}
60
61/* eslint-disable no-magic-numbers, max-params */
62function addFallbackHandler(server) {
63 // Handle 404 errors.
64 // Note: the react application middleware hands 404 paths, but it is good to
65 // have this backup for paths not handled by the universal middleware. For
66 // example you may bind a /api path to express.
67 server.use(function (request, response) {
68 // eslint-disable-line no-unused-vars,max-len
69 response.status(404).send("Sorry, that resource was not found.");
70 });
71
72 // Handle all other errors (i.e. 500).
73 // Note: You must provide specify all 4 parameters on this callback function
74 // even if they aren't used, otherwise it won't be used.
75 server.use(function (error, request, response) {
76 if (error) {
77 /* eslint-disable no-console */
78 console.log(error);
79 console.log(error.stack);
80 }
81
82 response.status(500).send("Sorry, an unexpected error occurred.");
83 });
84}
85
86function addSecurityMiddleware(server, _ref) {
87 var _ref$enableNonce = _ref.enableNonce,
88 enableNonce = _ref$enableNonce === undefined ? true : _ref$enableNonce,
89 _ref$enableCSP = _ref.enableCSP,
90 enableCSP = _ref$enableCSP === undefined ? true : _ref$enableCSP;
91
92 if (enableNonce) {
93 /* eslint-disable max-params */
94
95 // Attach a unique "nonce" to every response. This allows use to declare
96 // inline scripts as being safe for execution against our content security policy.
97 // @see https://helmetjs.github.io/docs/csp/
98 server.use(function (request, response, next) {
99 response.locals.nonce = uuid();
100 next();
101 });
102 }
103
104 // Don't expose any software information to hackers.
105 server.disable("x-powered-by");
106
107 // Prevent HTTP Parameter pollution.
108 server.use(parameterProtection());
109
110 // Content Security Policy (CSP)
111 //
112 // If you are unfamiliar with CSPs then I highly recommend that you do some
113 // reading on the subject:
114 // - https://content-security-policy.com/
115 // - https://developers.google.com/web/fundamentals/security/csp/
116 // - https://developer.mozilla.org/en/docs/Web/Security/CSP
117 // - https://helmetjs.github.io/docs/csp/
118 //
119 // If you are relying on scripts/styles/assets from other servers (internal or
120 // external to your company) then you will need to explicitly configure the
121 // CSP below to allow for this. For example you can see I have had to add
122 // the polyfill.io CDN in order to allow us to use the polyfill script.
123 // It can be a pain to manage these, but it's a really great habit to get in
124 // to.
125 //
126 // You may find CSPs annoying at first, but it is a great habit to build.
127 // The CSP configuration is an optional item for helmet, however you should
128 // not remove it without making a serious consideration that you do not require
129 // the added security.
130 var cspConfig = enableCSP ? {
131 directives: {
132 defaultSrc: ["'self'"],
133
134 scriptSrc: [
135 // Allow scripts hosted from our application.
136 "'self'",
137
138 // Note: We will execution of any inline scripts that have the following
139 // nonce identifier attached to them.
140 // This is useful for guarding your application whilst allowing an inline
141 // script to do data store rehydration (redux/mobx/apollo) for example.
142 // @see https://helmetjs.github.io/docs/csp/
143 function (request, response) {
144 return "'nonce-" + response.locals.nonce + "'";
145 },
146
147 // Required for eval-source-maps (devtool in webpack)
148 process.env.NODE_ENV === "development" ? "'unsafe-eval'" : ""].filter(function (value) {
149 return value !== "";
150 }),
151
152 styleSrc: ["'self'", "'unsafe-inline'", "blob:"],
153 imgSrc: ["'self'", "data:"],
154 fontSrc: ["'self'", "data:"],
155
156 // Note: Setting this to stricter than * breaks the service worker. :(
157 // I can't figure out how to get around this, so if you know of a safer
158 // implementation that is kinder to service workers please let me know.
159 // ["'self'", 'ws:'],
160 connectSrc: ["*"],
161
162 // objectSrc: [ "'none'" ],
163 // mediaSrc: [ "'none'" ],
164
165 childSrc: ["'self'"]
166 }
167 } : null;
168
169 if (enableCSP) {
170 server.use(helmet.contentSecurityPolicy(cspConfig));
171 }
172
173 // The xssFilter middleware sets the X-XSS-Protection header to prevent
174 // reflected XSS attacks.
175 // @see https://helmetjs.github.io/docs/xss-filter/
176 server.use(helmet.xssFilter());
177
178 // Frameguard mitigates clickjacking attacks by setting the X-Frame-Options header.
179 // @see https://helmetjs.github.io/docs/frameguard/
180 server.use(helmet.frameguard("deny"));
181
182 // Sets the X-Download-Options to prevent Internet Explorer from executing
183 // downloads in your site’s context.
184 // @see https://helmetjs.github.io/docs/ienoopen/
185 server.use(helmet.ieNoOpen());
186
187 // Don’t Sniff Mimetype middleware, noSniff, helps prevent browsers from trying
188 // to guess (“sniff”) the MIME type, which can have security implications. It
189 // does this by setting the X-Content-Type-Options header to nosniff.
190 // @see https://helmetjs.github.io/docs/dont-sniff-mimetype/
191 server.use(helmet.noSniff());
192}
193
194var defaultLocale = {
195 "default": "en-US",
196 supported: ["en-US"]
197};
198
199var defaultStatic = {
200 "public": "/static/",
201 path: "build/client"
202};
203
204function createExpressServer(_ref) {
205 var _ref$localeConfig = _ref.localeConfig,
206 localeConfig = _ref$localeConfig === undefined ? defaultLocale : _ref$localeConfig,
207 _ref$staticConfig = _ref.staticConfig,
208 staticConfig = _ref$staticConfig === undefined ? defaultStatic : _ref$staticConfig,
209 _ref$afterSecurity = _ref.afterSecurity,
210 afterSecurity = _ref$afterSecurity === undefined ? [] : _ref$afterSecurity,
211 _ref$beforeFallback = _ref.beforeFallback,
212 beforeFallback = _ref$beforeFallback === undefined ? [] : _ref$beforeFallback,
213 _ref$enableCSP = _ref.enableCSP,
214 enableCSP = _ref$enableCSP === undefined ? false : _ref$enableCSP,
215 _ref$enableNonce = _ref.enableNonce,
216 enableNonce = _ref$enableNonce === undefined ? false : _ref$enableNonce;
217
218 // Create our express based server.
219 var server = express();
220
221 addErrorMiddleware(server);
222 addSecurityMiddleware(server, { enableCSP: enableCSP, enableNonce: enableNonce });
223
224 // Allow for some early additions for middleware
225 if (afterSecurity.length > 0) {
226 afterSecurity.forEach(function (middleware) {
227 if (middleware instanceof Array) {
228 server.use.apply(server, middleware);
229 } else {
230 server.use(middleware);
231 }
232 });
233 }
234
235 addCoreMiddleware(server, { locale: localeConfig });
236
237 // Configure static serving of our webpack bundled client files.
238 if (staticConfig) {
239 server.use(staticConfig["public"], express["static"](staticConfig.path));
240 }
241
242 // Allow for some late additions for middleware
243 if (beforeFallback.length > 0) {
244 beforeFallback.forEach(function (middleware) {
245 if (middleware instanceof Array) {
246 server.use.apply(server, middleware);
247 } else {
248 server.use(middleware);
249 }
250 });
251 }
252
253 // For all things which did not went well.
254 addFallbackHandler(server);
255
256 return server;
257}
258
259// Initialize environment configuration
260dotenv.config();
261
262exports.addCoreMiddleware = addCoreMiddleware;
263exports.addErrorMiddleware = addErrorMiddleware;
264exports.addFallbackHandler = addFallbackHandler;
265exports.addSecurityMiddleware = addSecurityMiddleware;
266exports.createExpressServer = createExpressServer;
267//# sourceMappingURL=index.cjs.js.map