app.js (2020B)
1 import express from 'express'; 2 import rateLimit from 'express-rate-limit'; 3 import { MSG } from './messages.js'; 4 import { 5 getAllowedOrigins, 6 parseAllowedOrigins, 7 setAllowedOrigins, 8 } from './originGuard.js'; 9 import documentsRouter from './routes/documents.js'; 10 11 export function createApp(options = {}) { 12 const corsOrigin = options.corsOrigin ?? process.env.CORS_ORIGIN?.trim() ?? ''; 13 const shareAllowedOrigins = parseAllowedOrigins( 14 options.shareAllowedOrigins ?? process.env.SHARE_ALLOWED_ORIGINS ?? '', 15 ); 16 setAllowedOrigins(shareAllowedOrigins); 17 18 const app = express(); 19 app.set('trust proxy', 1); 20 21 if (corsOrigin) { 22 app.use((req, res, next) => { 23 const origin = req.headers.origin; 24 if (origin === corsOrigin) { 25 res.setHeader('Access-Control-Allow-Origin', origin); 26 res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); 27 res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); 28 } 29 if (req.method === 'OPTIONS') { 30 return res.sendStatus(204); 31 } 32 next(); 33 }); 34 } 35 36 app.use(express.json({ limit: '1.1mb' })); 37 38 const apiLimiter = rateLimit({ 39 windowMs: 60 * 1000, 40 max: 60, 41 standardHeaders: true, 42 legacyHeaders: false, 43 message: { 44 error: 'RATE_LIMIT', 45 message: MSG.RATE_LIMIT, 46 }, 47 }); 48 49 app.use('/api', apiLimiter, documentsRouter); 50 51 app.use((err, _req, res, next) => { 52 if (err instanceof SyntaxError && 'body' in err) { 53 return res.status(400).json({ 54 error: 'INVALID_JSON', 55 message: MSG.INVALID_JSON, 56 }); 57 } 58 next(err); 59 }); 60 61 app.use((err, _req, res, _next) => { 62 if (err?.type === 'entity.too.large') { 63 return res.status(413).json({ 64 error: 'CONTENT_TOO_LARGE', 65 message: MSG.CONTENT_TOO_LARGE, 66 }); 67 } 68 console.error(err); 69 res.status(500).json({ 70 error: 'INTERNAL_ERROR', 71 message: MSG.INTERNAL_ERROR, 72 }); 73 }); 74 75 return app; 76 } 77 78 export { getAllowedOrigins };