diff --git a/client/src/lib/sandboxed-mosaico-root.js b/client/src/lib/sandboxed-mosaico-root.js index 3109d08d..6e47375d 100644 --- a/client/src/lib/sandboxed-mosaico-root.js +++ b/client/src/lib/sandboxed-mosaico-root.js @@ -82,6 +82,12 @@ class MosaicoSandbox extends Component { }; }); + // Custom convertedUrl (https://github.com/voidlabs/mosaico/blob/a359e263f1af5cf05e2c2d56c771732f2ef6c8c6/src/js/app.js#L42) + // which does not complain about mismatch of domains between TRUSTED and PUBLIC + plugins.push(viewModel => { + ko.bindingHandlers.wysiwygSrc.convertedUrl = (src, method, width, height) => getTrustedUrl(`mosaico/img?src=${encodeURIComponent(src)}&method=${encodeURIComponent(method)}¶ms=${width},${height}`); + }); + plugins.unshift(vm => { // This is an override of the default paths in Mosaico vm.logoPath = getTrustedUrl('static/mosaico/img/mosaico32.png'); diff --git a/server/app-builder.js b/server/app-builder.js index a9243f4a..55c84c50 100644 --- a/server/app-builder.js +++ b/server/app-builder.js @@ -320,93 +320,49 @@ function createApp(appType) { app.use('/', index.getRouter(appType)); - // Error handlers - if (app.get('env') === 'development' || app.get('env') === 'test') { - // development error handler - // will print stacktrace - app.use((err, req, res, next) => { - if (!err) { - return next(); + app.use((err, req, res, next) => { + if (!err) { + return next(); + } + + if (req.needsRESTJSONResponse) { + const resp = { + message: err.message, + error: config.sendStacktracesToClient ? err : {} + }; + + if (err instanceof interoperableErrors.InteroperableError) { + resp.type = err.type; + resp.data = err.data; } - if (req.needsRESTJSONResponse) { - const resp = { - message: err.message, - error: err - }; + log.verbose('HTTP', err); + res.status(err.status || 500).json(resp); - if (err instanceof interoperableErrors.InteroperableError) { - resp.type = err.type; - resp.data = err.data; - } + } else if (req.needsAPIJSONResponse) { + const resp = { + error: err.message || err, + data: [] + }; - res.status(err.status || 500).json(resp); + log.verbose('HTTP', err); + return res.status(err.status || 500).json(resp); - } else if (req.needsAPIJSONResponse) { - const resp = { - error: err.message || err, - data: [] - }; - - return status(err.status || 500).json(resp); + } else { + // TODO: Render interoperable errors using a special client that does internationalization of the error message + if (err instanceof interoperableErrors.NotLoggedInError) { + return res.redirect(getTrustedUrl('/login?next=' + encodeURIComponent(req.originalUrl))); } else { - if (err instanceof interoperableErrors.NotLoggedInError) { - return res.redirect(getTrustedUrl('/login?next=' + encodeURIComponent(req.originalUrl))); - } else { - res.status(err.status || 500); - res.render('error', { - message: err.message, - error: err - }); - } - } - - }); - } else { - // production error handler - // no stacktraces leaked to user - app.use((err, req, res, next) => { - if (!err) { - return next(); - } - - if (req.needsRESTJSONResponse) { - const resp = { + log.verbose('HTTP', err); + res.status(err.status || 500); + res.render('error', { message: err.message, - error: {} - }; - - if (err instanceof interoperableErrors.InteroperableError) { - resp.type = err.type; - resp.data = err.data; - } - - res.status(err.status || 500).json(resp); - - } else if (req.needsAPIJSONResponse) { - const resp = { - error: err.message || err, - data: [] - }; - - return res.status(err.status || 500).json(resp); - - } else { - // TODO: Render interoperable errors using a special client that does internationalization of the error message - - if (err instanceof interoperableErrors.NotLoggedInError) { - return res.redirect(getTrustedUrl('/login?next=' + encodeURIComponent(req.originalUrl))); - } else { - res.status(err.status || 500); - res.render('error', { - message: err.message, - error: {} - }); - } + error: config.sendStacktracesToClient ? err : {} + }); } - }); - } + } + }); return app; } diff --git a/server/config/default.yaml b/server/config/default.yaml index 36cf8f2f..9bc88cf3 100644 --- a/server/config/default.yaml +++ b/server/config/default.yaml @@ -73,6 +73,7 @@ redis: log: # silly|verbose|info|http|warn|error|silent level: info + sendStacktracesToClient: false www: # HTTP port to listen on for trusted requests (logged-in users) diff --git a/server/index.js b/server/index.js index 5a063a28..09167f24 100644 --- a/server/index.js +++ b/server/index.js @@ -24,6 +24,7 @@ const { AppType } = require('../shared/app'); const builtinZoneMta = require('./lib/builtin-zone-mta'); const { uploadedFilesDir } = require('./lib/file-helpers'); +const { filesDir } = require('./models/files'); const trustedPort = config.www.trustedPort; const sandboxPort = config.www.sandboxPort; @@ -113,6 +114,7 @@ dbcheck(err => { // Check if database needs upgrading before starting the server startHTTPServer(AppType.SANDBOXED, 'sandbox', sandboxPort, () => startHTTPServer(AppType.PUBLIC, 'public', publicPort, async () => { + await privilegeHelpers.ensureMailtrainDir(filesDir); await privilegeHelpers.ensureMailtrainDir(uploadedFilesDir); privilegeHelpers.dropRootPrivileges(); diff --git a/server/routes/sandboxed-mosaico.js b/server/routes/sandboxed-mosaico.js index 20de35de..aa8d7755 100644 --- a/server/routes/sandboxed-mosaico.js +++ b/server/routes/sandboxed-mosaico.js @@ -156,7 +156,6 @@ function getRouter(appType) { // This is a fallback to versafix-1 if the block thumbnail is not defined by the template router.use('/templates/:mosaicoTemplateId/edres', express.static(path.join(__dirname, '..', '..', 'client', 'static', 'mosaico', 'templates', 'versafix-1', 'edres'))); - fileHelpers.installUploadHandler(router, '/upload/:type/:entityId', files.ReplacementBehavior.RENAME, null, 'file', resp => { return { files: resp.files.map(f => ({name: f.name, url: f.url, size: f.size, thumbnailUrl: f.thumbnailUrl}))