Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,36 @@

package org.apache.roller.weblogger.ui.struts2.editor;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.util.DateUtil;
import org.apache.roller.util.RollerConstants;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.business.MediaFileManager;
import org.apache.roller.weblogger.business.WebloggerFactory;
import org.apache.roller.weblogger.business.WeblogEntryManager;
import org.apache.roller.weblogger.business.plugins.PluginManager;
import org.apache.roller.weblogger.business.plugins.entry.WeblogEntryPlugin;
import org.apache.roller.weblogger.business.search.IndexManager;
import org.apache.roller.weblogger.config.WebloggerConfig;
import org.apache.roller.weblogger.config.WebloggerRuntimeConfig;
import org.apache.roller.weblogger.pojos.GlobalPermission;
import org.apache.roller.weblogger.pojos.MediaFile;
import org.apache.roller.weblogger.pojos.MediaFileDirectory;
import org.apache.roller.weblogger.pojos.WeblogCategory;
import org.apache.roller.weblogger.pojos.WeblogEntry;
import org.apache.roller.weblogger.pojos.WeblogEntry.PubStatus;
Expand All @@ -47,7 +58,10 @@
import org.apache.roller.weblogger.ui.core.plugins.WeblogEntryEditor;
import org.apache.roller.weblogger.ui.struts2.util.UIAction;
import org.apache.roller.weblogger.util.EnclosureMetadata;
import org.apache.roller.weblogger.util.InlineImageData;
import org.apache.roller.weblogger.util.MailUtil;
import org.apache.roller.weblogger.util.RollerMessages;
import org.apache.roller.weblogger.util.RollerMessages.RollerMessage;
import org.apache.roller.weblogger.util.cache.CacheManager;
import org.apache.struts2.convention.annotation.AllowedMethods;
import org.apache.struts2.interceptor.validation.SkipValidation;
Expand Down Expand Up @@ -200,7 +214,69 @@ String save() {
return failedSave();
}

String submittedText = getBean().getText();
String submittedSummary = getBean().getSummary();
List<MediaFile> createdImages = new ArrayList<>();
boolean entrySaved = false;
try {
Map<String, InlineImageData.Image> images = new HashMap<>();
List<InlineImageData.Source> textImages = InlineImageData.findSources(submittedText);
List<InlineImageData.Source> summaryImages = InlineImageData.findSources(submittedSummary);
boolean keepInline = WebloggerConfig.getBooleanProperty(
"weblog.inlineImages.preferInline")
|| !WebloggerRuntimeConfig.getBooleanProperty("uploads.enabled")
|| !getActionWeblog().hasUserPermission(
getAuthenticatedUser(), WeblogPermission.POST);
long maxUploadBytes = 0;
if (!keepInline && (!textImages.isEmpty() || !summaryImages.isEmpty())) {
maxUploadBytes = (long) (RollerConstants.ONE_MB_IN_BYTES
* new BigDecimal(WebloggerRuntimeConfig.getProperty(
"uploads.file.maxsize")).doubleValue());
}
if (!validateInlineImages(textImages, images, keepInline, maxUploadBytes)
|| !validateInlineImages(summaryImages, images, keepInline,
maxUploadBytes)) {
return failedSave();
}
if (!images.isEmpty()) {
if (keepInline) {
String inlineText = normalizeInlineSources(submittedText,
textImages);
String inlineSummary = normalizeInlineSources(submittedSummary,
summaryImages);
if (!inlineFieldFits(inlineText, textImages)
|| !inlineFieldFits(inlineSummary, summaryImages)) {
return failedSave();
}
getBean().setText(inlineText);
getBean().setSummary(inlineSummary);
} else {
MediaFileManager mediaManager = WebloggerFactory.getWeblogger()
.getMediaFileManager();
MediaFileDirectory directory = mediaManager
.getDefaultMediaFileDirectory(getActionWeblog());
if (directory == null) {
directory = mediaManager.createDefaultMediaFileDirectory(
getActionWeblog());
}
Map<String, String> mediaUrls = new HashMap<>();
getBean().setText(replaceInlineImages(submittedText,
textImages, images, mediaUrls, directory,
mediaManager, createdImages));
if (!hasActionErrors()) {
getBean().setSummary(replaceInlineImages(submittedSummary,
summaryImages, images, mediaUrls, directory,
mediaManager, createdImages));
}
if (hasActionErrors()) {
getBean().setText(submittedText);
getBean().setSummary(submittedSummary);
removeCreatedImages(mediaManager, createdImages);
return failedSave();
}
}
}

WeblogEntryManager weblogEntryManager = WebloggerFactory.getWeblogger()
.getWeblogEntryManager();

Expand Down Expand Up @@ -264,6 +340,7 @@ String save() {
log.debug("Saving entry");
weblogEntryManager.saveWeblogEntry(weblogEntry);
WebloggerFactory.getWeblogger().flush();
entrySaved = true;

// notify search of the new entry
if (weblogEntry.isPublished()) {
Expand Down Expand Up @@ -298,12 +375,141 @@ String save() {

} catch (Exception e) {
log.error("Error saving new entry", e);
if (!entrySaved) {
getBean().setText(submittedText);
getBean().setSummary(submittedSummary);
removeCreatedImages(WebloggerFactory.getWeblogger()
.getMediaFileManager(), createdImages);
}
addError("generic.error.check.logs");
}
}
return failedSave();
}

private boolean validateInlineImages(List<InlineImageData.Source> sources,
Map<String, InlineImageData.Image> images, boolean keepInline,
long maxUploadBytes) {
for (InlineImageData.Source source : sources) {
if (!keepInline && InlineImageData.exceedsUploadLimit(
source.getValue(), maxUploadBytes)) {
addError("weblogEdit.inlineImageUploadTooLarge");
return false;
}
InlineImageData.Image image = keepInline
? InlineImageData.parse(source.getValue())
: InlineImageData.parseForUpload(source.getValue(),
maxUploadBytes);
if (image == null) {
addError("weblogEdit.inlineImageInvalid");
return false;
}
images.put(source.getValue(), image);
}
return true;
}

private boolean inlineFieldFits(String html, List<InlineImageData.Source> sources) {
if (!sources.isEmpty() && html.getBytes(StandardCharsets.UTF_8).length
> InlineImageData.MAX_FIELD_BYTES) {
addError("weblogEdit.inlineImageTooLarge");
return false;
}
return true;
}

private String normalizeInlineSources(String html,
List<InlineImageData.Source> sources) {
if (html == null || sources.isEmpty()) {
return html;
}
StringBuilder result = new StringBuilder(html.length());
int cursor = 0;
for (InlineImageData.Source source : sources) {
result.append(html, cursor, source.getStart());
result.append("src=\"").append(source.getValue()).append('"');
cursor = source.getEnd();
}
result.append(html, cursor, html.length());
return result.toString();
}

private String replaceInlineImages(String html,
List<InlineImageData.Source> sources,
Map<String, InlineImageData.Image> images,
Map<String, String> mediaUrls, MediaFileDirectory directory,
MediaFileManager mediaManager, List<MediaFile> createdImages)
throws WebloggerException {
if (html == null || sources.isEmpty()) {
return html;
}
StringBuilder result = new StringBuilder(html.length());
int cursor = 0;
for (InlineImageData.Source source : sources) {
String url = mediaUrls.get(source.getValue());
if (url == null) {
InlineImageData.Image image = images.get(source.getValue());
String name = "entry-image-" + UUID.randomUUID() + "."
+ image.getExtension();
RollerMessages errors = new RollerMessages();
if (!WebloggerFactory.getWeblogger().getFileContentManager()
.canSave(getActionWeblog(), name, image.getContentType(),
image.getBytes().length, errors)) {
addMediaErrors(errors);
return html;
}
MediaFile media = new MediaFile();
media.setName(name);
media.setWeblog(getActionWeblog());
media.setDirectory(directory);
media.setLength(image.getBytes().length);
media.setContentType(image.getContentType());
media.setInputStream(new ByteArrayInputStream(image.getBytes()));
mediaManager.createMediaFile(getActionWeblog(), media, errors);
if (errors.getErrorCount() > 0) {
addMediaErrors(errors);
return html;
}
createdImages.add(media);
url = media.getPermalink();
mediaUrls.put(source.getValue(), url);
}
result.append(html, cursor, source.getStart());
result.append("src=\"").append(url).append('"');
cursor = source.getEnd();
}
result.append(html, cursor, html.length());
return result.toString();
}

private void addMediaErrors(RollerMessages errors) {
for (Iterator<RollerMessage> it = errors.getErrors(); it.hasNext();) {
RollerMessage message = it.next();
String[] args = message.getArgs();
addError(message.getKey(), args == null
? Collections.emptyList() : java.util.Arrays.asList(args));
}
}

private void removeCreatedImages(MediaFileManager mediaManager,
List<MediaFile> createdImages) {
for (MediaFile image : createdImages) {
try {
mediaManager.removeMediaFile(getActionWeblog(), image);
} catch (WebloggerException cleanupError) {
log.warn("Could not remove an image from a failed entry save", cleanupError);
}
}
if (!createdImages.isEmpty()) {
try {
WebloggerFactory.getWeblogger().flush();
} catch (WebloggerException cleanupError) {
log.warn("Could not flush image cleanup after a failed entry save",
cleanupError);
}
}
}

EnclosureMetadata validateEnclosure() {
if (StringUtils.isEmpty(getBean().getEnclosureURL())) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ public static SanitizeResult sanitizer(String html, Pattern allowedTags, Pattern
} else if (tag.matches("img|embed") && "src".equals(attr)) {
// <img src="......">
String[] customSchemes = {"http", "https"};
if (new UrlValidator(customSchemes).isValid(val)) {
if (new UrlValidator(customSchemes).isValid(val)
|| ("img".equals(tag) && InlineImageData.parse(val) != null)) {
foundURL = true;
} else {
ret.invalidTags.add(attr + " " + val);
Expand Down Expand Up @@ -374,7 +375,7 @@ public static SanitizeResult sanitizer(String html, Pattern allowedTags, Pattern
private static List<String> tokenize(String html) {
List<String> tokens = new ArrayList<>();
int pos = 0;
String token = "";
StringBuilder token = new StringBuilder();
int len = html.length();
while (pos < len) {
char c = html.charAt(pos);
Expand All @@ -385,11 +386,11 @@ private static List<String> tokenize(String html) {
if ("<!--".equals(ahead)) {
//store the current token
if (token.length() > 0) {
tokens.add(token);
tokens.add(token.toString());
}

//clear the token
token = "";
token.setLength(0);

// search the end of <......>
int end = moveToMarkerEnd(pos, "-->", html);
Expand All @@ -402,27 +403,27 @@ private static List<String> tokenize(String html) {

//store the current token
if (token.length() > 0) {
tokens.add(token);
tokens.add(token.toString());
}

//clear the token
token = "";
token.setLength(0);

// serch the end of <......>
int end = moveToMarkerEnd(pos, ">", html);
tokens.add(html.substring(pos, end));
pos = end;

} else {
token = token + c;
token.append(c);
pos++;
}

}

//store the last token
if (token.length() > 0) {
tokens.add(token);
tokens.add(token.toString());
}

return tokens;
Expand Down
Loading
Loading