Fixes of bugs caused by the public endpoint.

This commit is contained in:
Tomas Bures 2018-09-29 22:07:24 +02:00
parent efbfa2b366
commit 213039c141
10 changed files with 79 additions and 52 deletions

View file

@ -1,15 +1,15 @@
### Front page
- Some dashboard
### Deletion
- Check/delete dependencies
### Templates
- Add MJML template editor
- Include GrapeJS with MJML support
- CKEditor to sandbox
- Add Files support to CKEditor
### Message delivery
- Better integration with ZoneMTA to allow multiple send configurations (with different DKIM) against one ZoneMTA instance via different HTTP configuration of ZoneMTA. This may need an extension of ZoneMTA to provide some header entry that identifies the campaign.
### Campaigns
- Statistics for a sent campaign
- List of sent RSS campaigns (?)

View file

@ -218,13 +218,12 @@ function createApp(appType) {
useWith404Fallback('/subscription', subscription);
useWith404Fallback('/links', links);
useWith404Fallback('/archive', archive);
useWith404Fallback('/files', files);
}
if (appType === AppType.TRUSTED || appType === AppType.SANDBOXED) {
// Regular endpoints
useWith404Fallback('/files', files);
useWith404Fallback('/mosaico', mosaico.getRouter(appType));
useWith404Fallback('/mosaico', mosaico.getRouter(appType));
if (appType === AppType.TRUSTED || appType === AppType.SANDBOXED) {
if (config.reports && config.reports.enabled === true) {
useWith404Fallback('/reports', reports);
}
@ -266,7 +265,7 @@ function createApp(appType) {
app.use('/', index.getRouter(appType));
// Error handlers
if (app.get('env') === 'development') {
if (app.get('env') === 'development' || app.get('env') === 'test') {
// development error handler
// will print stacktrace
app.use((err, req, res, next) => {

View file

@ -8,6 +8,7 @@ import styles from "./mosaico.scss";
import {UntrustedContentHost, parentRPC} from './untrusted';
import {Icon} from "./bootstrap-components";
import {
getPublicUrl,
getSandboxUrl,
getTrustedUrl
} from "./urls";
@ -105,12 +106,13 @@ export class MosaicoSandbox extends Component {
}
async exportState(method, params) {
const sandboxUrlBase = getSandboxUrl();
const trustedUrlBase = getTrustedUrl();
const sandboxUrlBase = getSandboxUrl();
const publicUrlBase = getPublicUrl();
return {
html: unbase(this.viewModel.exportHTML(), trustedUrlBase, sandboxUrlBase, true),
model: unbase(this.viewModel.exportJSON(), trustedUrlBase, sandboxUrlBase),
metadata: unbase(this.viewModel.exportMetadata(), trustedUrlBase, sandboxUrlBase)
html: unbase(this.viewModel.exportHTML(), trustedUrlBase, sandboxUrlBase, publicUrlBase, true),
model: unbase(this.viewModel.exportJSON(), trustedUrlBase, sandboxUrlBase, publicUrlBase),
metadata: unbase(this.viewModel.exportMetadata(), trustedUrlBase, sandboxUrlBase, publicUrlBase)
};
}
@ -155,10 +157,11 @@ export class MosaicoSandbox extends Component {
strings: window.mosaicoLanguageStrings
};
const sandboxUrlBase = getSandboxUrl();
const trustedUrlBase = getTrustedUrl();
const metadata = this.props.initialMetadata && JSON.parse(base(this.props.initialMetadata, trustedUrlBase, sandboxUrlBase));
const model = this.props.initialModel && JSON.parse(base(this.props.initialModel, trustedUrlBase, sandboxUrlBase));
const sandboxUrlBase = getSandboxUrl();
const publicUrlBase = getPublicUrl();
const metadata = this.props.initialMetadata && JSON.parse(base(this.props.initialMetadata, trustedUrlBase, sandboxUrlBase, publicUrlBase));
const model = this.props.initialModel && JSON.parse(base(this.props.initialModel, trustedUrlBase, sandboxUrlBase, publicUrlBase));
const template = this.props.templateId ? getSandboxUrl(`mosaico/templates/${this.props.templateId}/index.html`) : this.props.templatePath;
const allPlugins = plugins.concat(window.mosaicoPlugins);

View file

@ -51,7 +51,7 @@ class CampaignSender {
}
if (campaign.source === CampaignSource.TEMPLATE) {
this.template = templates.getByIdTx(tx, contextHelpers.getAdminContext(), this.campaign.data.sourceTemplate, false);
this.template = await templates.getByIdTx(tx, contextHelpers.getAdminContext(), this.campaign.data.sourceTemplate, false);
}
const attachments = await files.listTx(tx, contextHelpers.getAdminContext(), 'campaign', 'attachment', this.campaign.id);
@ -111,7 +111,7 @@ class CampaignSender {
if (replaceDataImgs) {
// replace data: images with embedded attachments
html = html.replace(/(<img\b[^>]* src\s*=[\s"']*)(data:[^"'>\s]+)/gi, (match, prefix, dataUri) => {
let cid = shortid.generate() + '-attachments@' + campaign.address.split('@').pop();
const cid = shortid.generate() + '-attachments@' + campaign.address.split('@').pop();
attachments.push({
path: dataUri,
cid

View file

@ -14,6 +14,8 @@ const { formatDate, formatBirthday, parseDate, parseBirthday } = require('../sha
const { getFieldColumn } = require('../shared/lists');
const { cleanupFromPost } = require('../lib/helpers');
const Handlebars = require('handlebars');
const { getTrustedUrl, getSandboxUrl, getPublicUrl } = require('../lib/urls');
const { getMergeTagsForBases } = require('../shared/templates');
const allowedKeysCreate = new Set(['name', 'key', 'default_value', 'type', 'group', 'settings']);
@ -228,7 +230,7 @@ fieldTypes['date'] = {
getHbsType: field => 'typeDate' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
forHbs: (field, value) => formatDate(field.settings.dateFormat, value),
parsePostValue: (field, value) => parseDate(field.settings.dateFormat, value),
render: (field, value) => value !== null && value.trim() !== '' ? formatDate(field.settings.dateFormat, value) : ''
render: (field, value) => value !== null ? formatDate(field.settings.dateFormat, value) : ''
};
fieldTypes['birthday'] = {
@ -243,7 +245,7 @@ fieldTypes['birthday'] = {
getHbsType: field => 'typeBirthday' + field.settings.dateFormat.charAt(0).toUpperCase() + field.settings.dateFormat.slice(1),
forHbs: (field, value) => formatBirthday(field.settings.dateFormat, value),
parsePostValue: (field, value) => parseBirthday(field.settings.dateFormat, value),
render: (field, value) => value !== null && value.trim() !== '' ? formatBirthday(field.settings.dateFormat, value) : ''
render: (field, value) => value !== null ? formatBirthday(field.settings.dateFormat, value) : ''
};
const groupedTypes = Object.keys(fieldTypes).filter(key => fieldTypes[key].grouped);
@ -694,7 +696,8 @@ async function forHbs(context, listId, subscription) { // assumes grouped subscr
function getMergeTags(fieldsGrouped, subscription) { // assumes grouped subscription
const mergeTags = {
'EMAIL': subscription.email
'EMAIL': subscription.email,
...getMergeTagsForBases(getTrustedUrl(), getSandboxUrl(), getPublicUrl())
};
for (const fld of fieldsGrouped) {

View file

@ -8,7 +8,7 @@ const fs = require('fs-extra-promise');
const path = require('path');
const interoperableErrors = require('../shared/interoperable-errors');
const entitySettings = require('../lib/entity-settings');
const {getTrustedUrl} = require('../lib/urls');
const {getPublicUrl} = require('../lib/urls');
const crypto = require('crypto');
const bluebird = require('bluebird');
@ -29,7 +29,7 @@ function getFilePath(type, subType, entityId, filename) {
}
function getFileUrl(context, type, subType, entityId, filename) {
return getTrustedUrl(`files/${type}/${subType}/${entityId}/${filename}`, context)
return getPublicUrl(`files/${type}/${subType}/${entityId}/${filename}`, context)
}
function getFilesTable(type, subType) {
@ -109,7 +109,7 @@ async function getFileByFilename(context, type, subType, entityId, name) {
}
async function getFileByUrl(context, url) {
const urlPrefix = getTrustedUrl('files/', context);
const urlPrefix = getPublicUrl('files/', context);
if (url.startsWith(urlPrefix)) {
const path = url.substring(urlPrefix.length);
const pathElem = path.split('/');

View file

@ -15,16 +15,14 @@ router.get('/:campaign/:list/:subscription', (req, res, next) => {
res.render('partials/tracking-scripts', {
layout: 'archive/layout-raw'
}, (err, scripts) => {
console.log(scripts);
console.log(err);
if (err) {
return next(err);
}
html = scripts ? html.replace(/<\/body\b/i, match => scripts + match) : html;
const htmlWithScripts = scripts ? html.replace(/<\/body\b/i, match => scripts + match) : html;
res.render('archive/view', {
layout: 'archive/layout-raw',
message: html
message: htmlWithScripts
});
});

View file

@ -23,7 +23,7 @@ const mosaicoTemplates = require('../models/mosaico-templates');
const contextHelpers = require('../lib/context-helpers');
const interoperableErrors = require('../shared/interoperable-errors');
const { getTrustedUrl, getSandboxUrl } = require('../lib/urls');
const { getTrustedUrl, getSandboxUrl, getPublicUrl } = require('../lib/urls');
const { base } = require('../shared/templates');
const { AppType } = require('../shared/app');
@ -134,7 +134,7 @@ function getRouter(appType) {
const tmpl = await mosaicoTemplates.getById(req.context, castToInteger(req.params.mosaicoTemplateId));
res.set('Content-Type', 'text/html');
res.send(base(tmpl.data.html, getTrustedUrl(), getSandboxUrl('', req.context)));
res.send(base(tmpl.data.html, getTrustedUrl(), getSandboxUrl('', req.context), getPublicUrl()));
});
// Mosaico looks for block thumbnails in edres folder relative to index.html of the template. We respond to such requests here.
@ -153,7 +153,7 @@ 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', 'public', 'mosaico', 'templates', 'versafix-1', 'edres')));
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');
@ -185,7 +185,7 @@ function getRouter(appType) {
if (config.language && config.language !== 'en') {
const lang = config.language.split('_')[0];
try {
const file = path.join(__dirname, '..', 'client', 'public', 'mosaico', 'lang', 'mosaico-' + lang + '.json');
const file = path.join(__dirname, '..', 'client', 'static', 'mosaico', 'lang', 'mosaico-' + lang + '.json');
languageStrings = await fsReadFile(file, 'utf8');
} catch (err) {
}
@ -205,7 +205,8 @@ function getRouter(appType) {
});
});
} else {
} else if (appType === AppType.TRUSTED || appType === AppType.PUBLIC) { // Mosaico editor loads the images from TRUSTED endpoint. This is hard to change because the index.html has to come from TRUSTED.
// So we serve /mosaico/img under both endpoints. There is no harm in it.
router.getAsync('/img', async (req, res) => {
const method = req.query.method;
const params = req.query.params;
@ -214,6 +215,7 @@ function getRouter(appType) {
// FIXME - cache the generated files !!!
if (method === 'placeholder') {
width = sanitizeSize(width, 1, 2048, 600, false);
height = sanitizeSize(height, 1, 2048, 300, false);
@ -228,7 +230,7 @@ function getRouter(appType) {
const mosaicoLegacyUrlPrefix = getTrustedUrl(`mosaico/uploads/`);
if (url.startsWith(mosaicoLegacyUrlPrefix)) {
filePath = path.join(__dirname, '..', 'client', 'public' , 'mosaico', 'uploads', url.substring(mosaicoLegacyUrlPrefix.length));
filePath = path.join(__dirname, '..', 'client', 'static' , 'mosaico', 'uploads', url.substring(mosaicoLegacyUrlPrefix.length));
} else {
const file = await files.getFileByUrl(contextHelpers.getAdminContext(), url);
filePath = file.path;

View file

@ -1,6 +1,6 @@
'use strict';
function base(text, trustedBaseUrl, sandboxBaseUrl) {
function _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl) {
if (trustedBaseUrl.endsWith('/')) {
trustedBaseUrl = trustedBaseUrl.substring(0, trustedBaseUrl.length - 1);
}
@ -9,32 +9,54 @@ function base(text, trustedBaseUrl, sandboxBaseUrl) {
sandboxBaseUrl = sandboxBaseUrl.substring(0, sandboxBaseUrl.length - 1);
}
text = text.split('[URL_BASE]').join(trustedBaseUrl);
text = text.split('[SANDBOX_URL_BASE]').join(sandboxBaseUrl);
text = text.split('[ENCODED_URL_BASE]').join(encodeURIComponent(trustedBaseUrl));
text = text.split('[ENCODED_SANDBOX_URL_BASE]').join(encodeURIComponent(sandboxBaseUrl));
if (publicBaseUrl.endsWith('/')) {
publicBaseUrl = publicBaseUrl.substring(0, publicBaseUrl.length - 1);
}
return {trustedBaseUrl, sandboxBaseUrl, publicBaseUrl};
}
function getMergeTagsForBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl) {
const bases = _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl);
return {
URL_BASE: bases.publicBaseUrl,
TRUSTED_URL_BASE: bases.trustedBaseUrl,
SANDBOX_URL_BASE: bases.sandboxBaseUrl,
ENCODED_URL_BASE: encodeURIComponent(bases.publicBaseUrl),
ENCODED_TRUSTED_URL_BASE: encodeURIComponent(bases.trustedBaseUrl),
ENCODED_SANDBOX_URL_BASE: encodeURIComponent(bases.sandboxBaseUrl)
};
}
function base(text, trustedBaseUrl, sandboxBaseUrl, publicBaseUrl) {
const bases = _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl);
text = text.split('[URL_BASE]').join(bases.publicBaseUrl);
text = text.split('[TRUSTED_URL_BASE]').join(bases.trustedBaseUrl);
text = text.split('[SANDBOX_URL_BASE]').join(bases.sandboxBaseUrl);
text = text.split('[ENCODED_URL_BASE]').join(encodeURIComponent(bases.publicBaseUrl));
text = text.split('[ENCODED_TRUSTED_URL_BASE]').join(encodeURIComponent(bases.trustedBaseUrl));
text = text.split('[ENCODED_SANDBOX_URL_BASE]').join(encodeURIComponent(bases.sandboxBaseUrl));
return text;
}
function unbase(text, trustedBaseUrl, sandboxBaseUrl, treatSandboxAsTrusted = false) {
if (trustedBaseUrl.endsWith('/')) {
trustedBaseUrl = trustedBaseUrl.substring(0, trustedBaseUrl.length - 1);
}
function unbase(text, trustedBaseUrl, sandboxBaseUrl, publicBaseUrl, treatAllAsPublic = false) {
const bases = _getBases(trustedBaseUrl, sandboxBaseUrl, publicBaseUrl);
if (sandboxBaseUrl.endsWith('/')) {
sandboxBaseUrl = sandboxBaseUrl.substring(0, sandboxBaseUrl.length - 1);
}
text = text.split(trustedBaseUrl).join('[URL_BASE]');
text = text.split(sandboxBaseUrl).join(treatSandboxAsTrusted ? '[URL_BASE]' : '[SANDBOX_URL_BASE]');
text = text.split(encodeURIComponent(trustedBaseUrl)).join('[ENCODED_URL_BASE]');
text = text.split(encodeURIComponent(sandboxBaseUrl)).join(treatSandboxAsTrusted ? '[ENCODED_URL_BASE]' : '[ENCODED_SANDBOX_URL_BASE]');
text = text.split(bases.publicBaseUrl).join('[URL_BASE]');
text = text.split(bases.trustedBaseUrl).join(treatAllAsPublic ? '[URL_BASE]' : '[TRUSTED_URL_BASE]');
text = text.split(bases.sandboxBaseUrl).join(treatAllAsPublic ? '[URL_BASE]' : '[SANDBOX_URL_BASE]');
text = text.split(encodeURIComponent(bases.publicBaseUrl)).join('[ENCODED_URL_BASE]');
text = text.split(encodeURIComponent(bases.trustedBaseUrl)).join(treatAllAsPublic ? '[ENCODED_URL_BASE]' : '[ENCODED_TRUSTED_URL_BASE]');
text = text.split(encodeURIComponent(bases.sandboxBaseUrl)).join(treatAllAsPublic ? '[ENCODED_URL_BASE]' : '[ENCODED_SANDBOX_URL_BASE]');
return text;
}
module.exports = {
base,
unbase
unbase,
getMergeTagsForBases
};

View file

@ -1,6 +1,6 @@
'use strict';
const anonymousRestrictedAccessToken = 'public';
const anonymousRestrictedAccessToken = 'anonymous';
module.exports = {
anonymousRestrictedAccessToken