const PUBLIC_RUNTIME_ALLOWED_PATH = '/'; const PUBLIC_RUNTIME_ENTITY_FIELDS = { projects: [ 'id', 'name', 'slug', 'description', 'logo_url', 'favicon_url', 'og_image_url', 'theme_config_json', 'custom_css_json', 'cdn_base_url', ], tour_pages: [ 'id', 'projectId', 'environment', 'source_key', 'name', 'slug', 'sort_order', 'background_image_url', 'background_video_url', 'background_audio_url', 'background_loop', 'requires_auth', 'ui_schema_json', ], project_audio_tracks: [ 'id', 'projectId', 'environment', 'source_key', 'name', 'slug', 'url', 'loop', 'volume', 'sort_order', 'is_enabled', ], }; const pickFields = (record, fields) => { if (!record || typeof record !== 'object') { return record; } // Convert Sequelize instance to plain object if needed const plainRecord = typeof record.get === 'function' ? record.get({ plain: true }) : record; return fields.reduce((acc, field) => { if (field in plainRecord && plainRecord[field] !== undefined) { acc[field] = plainRecord[field]; } return acc; }, {}); }; const isPublicRuntimeReadRequest = (req) => { return req.isRuntimePublicRequest === true && req.method === 'GET'; }; const blockNonPublicRuntimeListEndpoints = (req, res, next) => { if (!isPublicRuntimeReadRequest(req)) { return next(); } if (req.path !== PUBLIC_RUNTIME_ALLOWED_PATH) { return res.status(404).send({ message: 'Not found' }); } if (req.query.filetype === 'csv') { return res.status(404).send({ message: 'Not found' }); } return next(); }; const sanitizePublicRuntimeListResponse = (entityName) => { const fields = PUBLIC_RUNTIME_ENTITY_FIELDS[entityName] || []; return (req, res, next) => { if ( !isPublicRuntimeReadRequest(req) || req.path !== PUBLIC_RUNTIME_ALLOWED_PATH || fields.length === 0 ) { return next(); } const originalSend = res.send.bind(res); res.send = (body) => { if (!body || typeof body !== 'object') { return originalSend(body); } if (!Array.isArray(body.rows)) { return originalSend(body); } const sanitizedRows = body.rows.map((row) => pickFields(row, fields)); return originalSend({ ...body, rows: sanitizedRows, }); }; return next(); }; }; module.exports = { blockNonPublicRuntimeListEndpoints, sanitizePublicRuntimeListResponse, };