mirror of
https://github.com/octoleo/plantuml.git
synced 2024-12-22 19:09:03 +00:00
wip
This commit is contained in:
parent
d741fad9d6
commit
dbaaa0165e
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
// s = removeXmlHeader(s);
|
||||
}
|
||||
|
||||
private String removeXmlHeader(String s) {
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ public class Version {
|
||||
}
|
||||
|
||||
public static int beta() {
|
||||
final int beta = 0;
|
||||
final int beta = 1;
|
||||
return beta;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user