This commit is contained in:
Arnaud Roques 2022-04-27 18:30:36 +02:00
parent d741fad9d6
commit dbaaa0165e
9 changed files with 78 additions and 80 deletions

View File

@ -72,32 +72,29 @@ public class FileSystem {
}
public SFile getFile(String nameOrPath) throws IOException {
if (isAbsolute(nameOrPath)) {
if (isAbsolute(nameOrPath))
return new SFile(nameOrPath).getCanonicalFile();
}
final SFile dir = getCurrentDir();
SFile filecurrent = null;
if (dir != null) {
filecurrent = dir.getAbsoluteFile().file(nameOrPath);
if (filecurrent.exists()) {
if (filecurrent.exists())
return filecurrent.getCanonicalFile();
}
}
for (SFile d : SecurityUtils.getPath(SecurityUtils.PATHS_INCLUDES)) {
assert d.isDirectory();
final SFile file = d.file(nameOrPath);
if (file.exists()) {
if (file.exists())
return file.getCanonicalFile();
}
}
for (SFile d : SecurityUtils.getPath(SecurityUtils.PATHS_CLASSES)) {
assert d.isDirectory();
final SFile file = d.file(nameOrPath);
if (file.exists()) {
if (file.exists())
return file.getCanonicalFile();
}
}
if (dir == null) {
assert filecurrent == null;

View File

@ -5,12 +5,12 @@
* (C) Copyright 2009-2023, Arnaud Roques
*
* Project Info: http://plantuml.com
*
*
* If you like this project or if you find it useful, you can support us at:
*
*
* http://plantuml.com/patreon (only 1$ per month!)
* http://plantuml.com/paypal
*
*
* This file is part of PlantUML.
*
* PlantUML is free software; you can redistribute it and/or modify it

View File

@ -120,38 +120,38 @@ public class AtomImg extends AbstractAtom implements Atom {
try {
// Check if valid URL
if (src.startsWith("http:") || src.startsWith("https:")) {
if (src.endsWith(".svg")) {
if (src.endsWith(".svg"))
return buildSvgFromUrl(src, fc, SURL.create(src), scale, url);
}
return buildRasterFromUrl(src, fc, SURL.create(src), scale, url);
}
final SFile f = FileSystem.getInstance().getFile(src);
if (f.exists() == false) {
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) {
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
return AtomTextUtils.createLegacy("(File not found: " + f.getPrintablePath() + ")", fc);
}
return AtomTextUtils.createLegacy("(Cannot decode)", fc);
}
if (f.getName().endsWith(".svg")) {
final String tmp = FileUtils.readSvg(f);
if (tmp == null) {
if (tmp == null)
return AtomTextUtils.createLegacy("(Cannot decode)", fc);
}
return new AtomImgSvg(new TileImageSvg(tmp));
}
final BufferedImage read = f.readRasterImageFromFile();
if (read == null) {
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) {
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
return AtomTextUtils.createLegacy("(Cannot decode: " + f.getPrintablePath() + ")", fc);
}
return AtomTextUtils.createLegacy("(Cannot decode)", fc);
}
return new AtomImg(f.readRasterImageFromFile(), scale, url, src);
} catch (IOException e) {
e.printStackTrace();
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE) {
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
return AtomTextUtils.createLegacy("ERROR " + e.toString(), fc);
}
return AtomTextUtils.createLegacy("ERROR", fc);
}
}

View File

@ -82,7 +82,13 @@ public class SFile implements Comparable<SFile> {
@Override
public String toString() {
return "Image42";
if (SecurityUtils.getSecurityProfile() == SecurityProfile.UNSECURE)
try {
return internal.getCanonicalPath();
} catch (IOException e) {
return internal.getAbsolutePath();
}
return super.toString();
}
public SFile(String nameOrPath) {
@ -174,7 +180,7 @@ public class SFile implements Comparable<SFile> {
final File[] tmp = internal.listFiles();
if (tmp == null)
return Collections.emptyList();
final List<SFile> result = new ArrayList<>(tmp.length);
for (File f : tmp) {
result.add(new SFile(f));
@ -263,7 +269,7 @@ public class SFile implements Comparable<SFile> {
if (isInAllowList(SecurityUtils.getPath(SecurityUtils.PATHS_INCLUDES)))
return true;
if (isInAllowList(SecurityUtils.getPath(SecurityUtils.PATHS_ALLOWED)))
if (isInAllowList(SecurityUtils.getPath(SecurityUtils.ALLOWLIST_LOCAL_PATHS)))
return true;
if (SecurityUtils.getSecurityProfile() == SecurityProfile.INTERNET)

View File

@ -110,7 +110,7 @@ public class SURL {
/**
* Regex to remove the UserInfo part from a URL.
*/
private static final Pattern PATTERN_USERINFO = Pattern.compile("(^https?://)(.*@)(.*)");
private static final Pattern PATTERN_USERINFO = Pattern.compile("(^https?://)([-_0-9a-zA-Z]+@)([^@]*)");
private static final ExecutorService EXE = Executors.newCachedThreadPool(new ThreadFactory() {
public Thread newThread(Runnable r) {
@ -229,7 +229,7 @@ public class SURL {
// We are UNSECURE anyway
return true;
if (isInAllowList())
if (isInUrlAllowList())
return true;
if (SecurityUtils.getSecurityProfile() == SecurityProfile.INTERNET) {
@ -244,16 +244,16 @@ public class SURL {
}
private boolean forbiddenURL(String full) {
if (full.matches("^https?://\\d+\\.\\d+\\.\\d+\\.\\d+.*"))
if (full.matches("^https?://[.0-9]+/.*"))
return true;
if (full.matches("^https?://[^.]+/.*"))
return true;
return false;
}
private boolean isInAllowList() {
private boolean isInUrlAllowList() {
final String full = cleanPath(internal.toString());
for (String allow : getAllowList())
for (String allow : getUrlAllowList())
if (full.startsWith(cleanPath(allow)))
return true;
@ -271,8 +271,8 @@ public class SURL {
return path;
}
private List<String> getAllowList() {
final String env = SecurityUtils.getenv(SecurityUtils.PATHS_ALLOWED);
private List<String> getUrlAllowList() {
final String env = SecurityUtils.getenv(SecurityUtils.ALLOWLIST_URL);
if (env == null)
return Collections.emptyList();

View File

@ -95,7 +95,12 @@ public class SecurityUtils {
/**
* Whitelist of paths from where scripts can load data.
*/
public static final String PATHS_ALLOWED = "plantuml.allowlist.path";
public static final String ALLOWLIST_LOCAL_PATHS = "plantuml.allowlist.path";
/**
* Whitelist of urls
*/
public static final String ALLOWLIST_URL = "plantuml.allowlist.url";
/**
* Paths to folders with security specific content (not allowed to read via

View File

@ -42,6 +42,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -642,19 +643,8 @@ public class SvgGraphics {
}
public void createXml(OutputStream os) throws TransformerException, IOException {
if (images.size() == 0) {
createXmlInternal(os);
return;
}
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
createXmlInternal(baos);
String s = new String(baos.toByteArray());
for (Map.Entry<String, String> ent : images.entrySet()) {
final String k = "<" + ent.getKey() + "/>";
s = s.replace(k, ent.getValue());
}
s = removeXmlHeader(s);
os.write(s.getBytes());
createXmlInternal(os);
// s = removeXmlHeader(s);
}
private String removeXmlHeader(String s) {
@ -673,7 +663,7 @@ public class SvgGraphics {
final int maxXscaled = (int) (maxX * scale);
final int maxYscaled = (int) (maxY * scale);
String style = "width:" + maxXscaled + "px;height:" + maxYscaled + "px;";
if (/*this.classesForDarkness.size() == 0 &&*/ backcolor != null)
if (/* this.classesForDarkness.size() == 0 && */ backcolor != null)
style += "background:" + backcolor + ";";
if (svgDimensionStyle) {
@ -894,17 +884,26 @@ public class SvgGraphics {
ensureVisible(x + image.getWidth(), y + image.getHeight());
}
private final Map<String, String> images = new HashMap<String, String>();
public void svgImage(UImageSvg image, double x, double y) {
// https://developer.mozilla.org/fr/docs/Web/SVG/Element/image
if (hidden == false) {
final Element elt = (Element) document.createElement("image");
elt.setAttribute("width", format(image.getWidth()));
elt.setAttribute("height", format(image.getHeight()));
elt.setAttribute("x", format(x));
elt.setAttribute("y", format(y));
String svg = manageScale(image);
final String pos = "<svg x=\"" + format(x) + "\" y=\"" + format(y) + "\">";
svg = pos + svg.substring(5);
final String key = "imagesvginlined" + image.getMD5Hex() + images.size();
final Element elt = (Element) document.createElement(key);
final String svgHeader = "<svg height=\"" + (int) (image.getHeight() * scale) + "\" width=\""
+ (int) (image.getWidth() * scale) + "\" xmlns=\"http://www.w3.org/2000/svg\" >";
svg = svgHeader + svg.substring(5);
final String s = toBase64(svg);
elt.setAttribute("xlink:href", "data:image/svg+xml;base64," + s);
getG().appendChild(elt);
images.put(key, svg);
}
ensureVisible(x, y);
ensureVisible(x + image.getData("width"), y + image.getData("height"));
@ -935,6 +934,11 @@ public class SvgGraphics {
return new String(Base64Coder.encode(data));
}
private String toBase64(String s) {
final byte data[] = s.getBytes(Charset.forName("UTF8"));
return new String(Base64Coder.encode(data));
}
// Shadow
private boolean withShadow = false;

View File

@ -43,37 +43,23 @@ import net.sourceforge.plantuml.SignatureUtils;
public class UImageSvg implements UShape {
private static final String EMPTY_SVG = "<svg width=10 height=10></svg>";
private final String svg;
private final double scale;
public UImageSvg(String svg, double scale) {
this.svg = clean(Objects.requireNonNull(svg));
this.svg = Objects.requireNonNull(svg);
this.scale = scale;
}
private String clean(final String svg) {
final String svg2 = svg.toLowerCase().replaceAll("\\s", "");
if (svg2.contains("<script>"))
return EMPTY_SVG;
if (svg2.contains("</script>"))
return EMPTY_SVG;
if (svg2.contains("<foreignobject"))
return EMPTY_SVG;
if (svg2.contains("</foreignobject>"))
return EMPTY_SVG;
return svg;
}
public String getMD5Hex() {
return SignatureUtils.getMD5Hex(svg);
}
public String getSvg(boolean raw) {
String result = svg;
if (raw) {
if (raw)
return result;
}
if (result.startsWith("<?xml")) {
final int idx = result.indexOf("<svg");
result = result.substring(idx);
@ -85,31 +71,31 @@ public class UImageSvg implements UShape {
final String style = extractSvgStyle();
if (style != null) {
final String background = extractBackground(style);
if (background != null) {
if (background != null)
result = result.replaceFirst("<g>", "<g><rect fill=\"" + background + "\" style=\"" + style + "\" /> ");
}
}
if (result.startsWith("<svg>") == false) {
if (result.startsWith("<svg>") == false)
throw new IllegalArgumentException();
}
return result;
}
private String extractBackground(String style) {
final Pattern p = Pattern.compile("background:([^;]+)");
final Matcher m = p.matcher(style);
if (m.find()) {
if (m.find())
return m.group(1);
}
return null;
}
private String extractSvgStyle() {
final Pattern p = Pattern.compile("(?i)\\<svg[^>]+style=\"([^\">]+)\"");
final Matcher m = p.matcher(svg);
if (m.find()) {
if (m.find())
return m.group(1);
}
return null;
}

View File

@ -80,7 +80,7 @@ public class Version {
}
public static int beta() {
final int beta = 0;
final int beta = 1;
return beta;
}