1
0
mirror of https://github.com/octoleo/plantuml.git synced 2024-11-26 06:46:45 +00:00
This commit is contained in:
Arnaud Roques 2022-01-27 18:08:03 +01:00
parent 9ae7706e5c
commit ddaacdf3f7
10 changed files with 156 additions and 149 deletions

View File

@ -104,23 +104,20 @@ public class Link extends WithLinkType implements Hideable, Removeable {
private Url url;
public String idCommentForSvg() {
if (type.looksLikeRevertedForSvg()) {
final String comment = getEntity1().getCodeGetName() + "-backto-" + getEntity2().getCodeGetName();
return comment;
}
if (type.looksLikeNoDecorAtAllSvg()) {
final String comment = getEntity1().getCodeGetName() + "-" + getEntity2().getCodeGetName();
return comment;
}
final String comment = getEntity1().getCodeGetName() + "-to-" + getEntity2().getCodeGetName();
return comment;
if (type.looksLikeRevertedForSvg())
return getEntity1().getCodeGetName() + "-backto-" + getEntity2().getCodeGetName();
if (type.looksLikeNoDecorAtAllSvg())
return getEntity1().getCodeGetName() + "-" + getEntity2().getCodeGetName();
return getEntity1().getCodeGetName() + "-to-" + getEntity2().getCodeGetName();
}
public UComment commentForSvg() {
if (type.looksLikeRevertedForSvg()) {
if (type.looksLikeRevertedForSvg())
return new UComment(
"reverse link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName());
}
return new UComment("link " + getEntity1().getCodeGetName() + " to " + getEntity2().getCodeGetName());
}
@ -158,33 +155,15 @@ public class Link extends WithLinkType implements Hideable, Removeable {
this.labeldistance = labeldistance;
this.labelangle = labelangle;
this.setSpecificColor(specificColor);
if (qualifier1 != null) {
if (qualifier1 != null)
((ILeaf) cl1).setNearDecoration(true);
}
if (qualifier2 != null) {
if (qualifier2 != null)
((ILeaf) cl2).setNearDecoration(true);
}
// if (type.getDecor2() == LinkDecor.EXTENDS) {
// setSametail(cl1.getUid());
// }
}
// private static boolean doWeHaveToRemoveUrlAtStart(Display label) {
// if (label.size() == 0) {
// return false;
// }
// final String s = label.get(0).toString();
// if (s.matches("^\\[\\[\\S+\\]\\].+$")) {
// return true;
// }
// return false;
// }
public Link getInv() {
// if (getLength() == 1) {
// final int x = cl1.getXposition();
// cl2.setXposition(x-1);
// }
final Link result = new Link(cl2, cl1, getType().getInversed(), label, length, qualifier2, qualifier1,
labeldistance, labelangle, getSpecificColor(), styleBuilder);
result.inverted = !this.inverted;
@ -193,6 +172,7 @@ public class Link extends WithLinkType implements Hideable, Removeable {
result.url = this.url;
result.linkConstraint = this.linkConstraint;
result.stereotype = stereotype;
result.visibilityModifier = visibilityModifier;
return result;
}
@ -216,9 +196,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public final boolean isInvis() {
if (type.isInvisible()) {
if (type.isInvisible())
return true;
}
return invis;
}
@ -227,12 +207,12 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public boolean isBetween(IEntity cl1, IEntity cl2) {
if (cl1.equals(this.cl1) && cl2.equals(this.cl2)) {
if (cl1.equals(this.cl1) && cl2.equals(this.cl2))
return true;
}
if (cl1.equals(this.cl2) && cl2.equals(this.cl1)) {
if (cl1.equals(this.cl2) && cl2.equals(this.cl1))
return true;
}
return false;
}
@ -259,40 +239,40 @@ public class Link extends WithLinkType implements Hideable, Removeable {
@Override
public LinkType getType() {
if (opale) {
if (opale)
return new LinkType(LinkDecor.NONE, LinkDecor.NONE);
}
if (getSametail() != null) {
if (getSametail() != null)
return new LinkType(LinkDecor.NONE, LinkDecor.NONE);
}
LinkType result = type;
if (OptionFlags.USE_INTERFACE_EYE1) {
if (isLollipopInterfaceEye(cl1)) {
if (isLollipopInterfaceEye(cl1))
type = type.withLollipopInterfaceEye1();
}
if (isLollipopInterfaceEye(cl2)) {
if (isLollipopInterfaceEye(cl2))
type = type.withLollipopInterfaceEye2();
}
}
return result;
}
private boolean isReallyGroup(IEntity ent) {
if (ent.isGroup() == false) {
if (ent.isGroup() == false)
return false;
}
final IGroup group = (IGroup) ent;
return group.getChildren().size() + group.getLeafsDirect().size() > 0;
}
public LinkType getTypePatchCluster() {
LinkType result = getType();
if (isReallyGroup(getEntity1())) {
if (isReallyGroup(getEntity1()))
result = result.withoutDecors2();
}
if (isReallyGroup(getEntity2())) {
if (isReallyGroup(getEntity2()))
result = result.withoutDecors1();
}
return result;
}
@ -302,12 +282,12 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
LinkType result = type;
if (OptionFlags.USE_INTERFACE_EYE1) {
if (isLollipopInterfaceEye(cl1)) {
if (isLollipopInterfaceEye(cl1))
type = type.withLollipopInterfaceEye1();
}
if (isLollipopInterfaceEye(cl2)) {
if (isLollipopInterfaceEye(cl2))
type = type.withLollipopInterfaceEye2();
}
}
return result;
}
@ -375,39 +355,39 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public boolean isAutoLinkOfAGroup() {
if (getEntity1().isGroup() == false) {
if (getEntity1().isGroup() == false)
return false;
}
if (getEntity2().isGroup() == false) {
if (getEntity2().isGroup() == false)
return false;
}
if (getEntity1() == getEntity2()) {
if (getEntity1() == getEntity2())
return true;
}
return false;
}
public boolean containsType(LeafType type) {
if (getEntity1().getLeafType() == type || getEntity2().getLeafType() == type) {
if (getEntity1().getLeafType() == type || getEntity2().getLeafType() == type)
return true;
}
return false;
}
public boolean contains(IEntity entity) {
if (getEntity1() == entity || getEntity2() == entity) {
if (getEntity1() == entity || getEntity2() == entity)
return true;
}
return false;
}
public IEntity getOther(IEntity entity) {
if (getEntity1() == entity) {
if (getEntity1() == entity)
return getEntity2();
}
if (getEntity2() == entity) {
if (getEntity2() == entity)
return getEntity1();
}
throw new IllegalArgumentException();
}
@ -455,9 +435,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public final LinkArrow getLinkArrow() {
if (inverted) {
if (inverted)
return linkArrow.reverse();
}
return linkArrow;
}
@ -495,28 +475,28 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public boolean sameConnections(Link other) {
if (this.cl1 == other.cl1 && this.cl2 == other.cl2) {
if (this.cl1 == other.cl1 && this.cl2 == other.cl2)
return true;
}
if (this.cl1 == other.cl2 && this.cl2 == other.cl1) {
if (this.cl1 == other.cl2 && this.cl2 == other.cl1)
return true;
}
return false;
}
public boolean doesTouch(Link other) {
if (this.cl1 == other.cl1) {
if (this.cl1 == other.cl1)
return true;
}
if (this.cl1 == other.cl2) {
if (this.cl1 == other.cl2)
return true;
}
if (this.cl2 == other.cl1) {
if (this.cl2 == other.cl1)
return true;
}
if (this.cl2 == other.cl2) {
if (this.cl2 == other.cl2)
return true;
}
return false;
}
@ -529,9 +509,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
}
public boolean hasUrl() {
if (Display.isNull(label) == false && label.hasUrl()) {
if (Display.isNull(label) == false && label.hasUrl())
return true;
}
return getUrl() != null;
}
@ -546,12 +526,12 @@ public class Link extends WithLinkType implements Hideable, Removeable {
public void setPortMembers(String port1, String port2) {
this.port1 = port1;
this.port2 = port2;
if (port1 != null) {
if (port1 != null)
((ILeaf) cl1).addPortShortName(port1);
}
if (port2 != null) {
if (port2 != null)
((ILeaf) cl2).addPortShortName(port2);
}
}
public final VisibilityModifier getVisibilityModifier() {
@ -581,9 +561,9 @@ public class Link extends WithLinkType implements Hideable, Removeable {
private LineLocation codeLine;
public String getCodeLine() {
if (codeLine == null) {
if (codeLine == null)
return null;
}
return "" + codeLine.getPosition();
}

View File

@ -43,6 +43,7 @@ import java.util.StringTokenizer;
import net.sourceforge.plantuml.BackSlash;
import net.sourceforge.plantuml.Log;
import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.ugraphic.ShadowManager;
import net.sourceforge.plantuml.ugraphic.UPath;
import net.sourceforge.plantuml.ugraphic.USegment;
@ -790,6 +791,10 @@ public class EpsGraphics {
}
public void openLink(String url) {
// javascript: security issue
if (SecurityUtils.ignoreThisLink(url))
return;
this.urlArea = new UrlArea(url);
}

View File

@ -78,11 +78,13 @@ public abstract class UGraphicDelegator implements UGraphic {
public ColorMapper getColorMapper() {
return ug.getColorMapper();
}
@Override
public void startUrl(Url url) {
ug.startUrl(url);
}
@Override
public void closeUrl() {
ug.closeUrl();
}

View File

@ -97,29 +97,29 @@ public class SecurityUtils {
public static final String PATHS_ALLOWED = "plantuml.allowlist.path";
/**
* Paths to folders with security specific content (not allowed to read via SFile).
* Paths to folders with security specific content (not allowed to read via
* SFile).
*/
public static final String PATHS_SECURITY = "plantuml.security.credentials.path";
public static final String SECURITY_ALLOW_NONSSL_AUTH = "plantuml.security.allowNonSSLAuth";
/**
* Standard BasicAuth authentication interceptor, to generate a SecurityAuthentication from credentials.
* Standard BasicAuth authentication interceptor, to generate a
* SecurityAuthentication from credentials.
*/
private static final SecurityAuthorizeManager PUBLIC_AUTH_MANAGER
= new SecurityDefaultNoopAuthorizeManager();
private static final SecurityAuthorizeManager PUBLIC_AUTH_MANAGER = new SecurityDefaultNoopAuthorizeManager();
/**
* Standard interceptor for public endpoint access.
*/
private static final SecurityAccessInterceptor PUBLIC_ACCESS_INTERCEPTOR
= new SecurityDefaultNoopAccessInterceptor();
private static final SecurityAccessInterceptor PUBLIC_ACCESS_INTERCEPTOR = new SecurityDefaultNoopAccessInterceptor();
/**
* Standard TokenAuth authorize manager, to generate a SecurityAuthentication from credentials.
* Standard TokenAuth authorize manager, to generate a SecurityAuthentication
* from credentials.
*/
private static final SecurityAuthorizeManager TOKEN_AUTH_MANAGER
= new TokenAuthAuthorizeManager();
private static final SecurityAuthorizeManager TOKEN_AUTH_MANAGER = new TokenAuthAuthorizeManager();
/**
* Standard token access interceptor.
@ -127,10 +127,10 @@ public class SecurityUtils {
private static final SecurityAccessInterceptor TOKEN_ACCESS_INTERCEPTOR = new TokenAuthAccessInterceptor();
/**
* Standard BasicAuth authorize manager, to generate a SecurityAuthentication from credentials.
* Standard BasicAuth authorize manager, to generate a SecurityAuthentication
* from credentials.
*/
private static final SecurityAuthorizeManager BASICAUTH_AUTH_MANAGER
= new BasicAuthAuthorizeManager();
private static final SecurityAuthorizeManager BASICAUTH_AUTH_MANAGER = new BasicAuthAuthorizeManager();
/**
* Standard BasicAuth access interceptor.
@ -140,14 +140,12 @@ public class SecurityUtils {
/**
* OAuth2 client credentials authorization manager.
*/
private static final SecurityAuthorizeManager OAUTH2_CLIENT_AUTH_MANAGER
= new OAuth2ClientAccessAuthorizeManager();
private static final SecurityAuthorizeManager OAUTH2_CLIENT_AUTH_MANAGER = new OAuth2ClientAccessAuthorizeManager();
/**
* OAuth2 resource owner authorization manager.
*/
private static final SecurityAuthorizeManager OAUTH2_RESOURCEOWNER_AUTH_MANAGER
= new OAuth2ResourceOwnerAccessAuthorizeManager();
private static final SecurityAuthorizeManager OAUTH2_RESOURCEOWNER_AUTH_MANAGER = new OAuth2ResourceOwnerAccessAuthorizeManager();
/**
* Standard 'bearer' OAuth2 access interceptor.
@ -168,15 +166,19 @@ public class SecurityUtils {
return current;
}
public static boolean getJavascriptUnsecure() {
final String env = getenv("PLANTUML_JAVASCRIPT_UNSECURE");
if ("true".equalsIgnoreCase(env)) {
public static boolean ignoreThisLink(String url) {
if (allowJavascriptInLink() == false && isJavascriptLink(url))
return true;
}
if ("false".equalsIgnoreCase(env)) {
return false;
}
return OptionFlags.ALLOW_INCLUDE;
return false;
}
private static boolean isJavascriptLink(String url) {
return url.toLowerCase().replaceAll("[^a-z]", "").startsWith("javascript");
}
private static boolean allowJavascriptInLink() {
final String env = getenv("PLANTUML_ALLOW_JAVASCRIPT_IN_LINK");
return "true".equalsIgnoreCase(env);
}
public static String getenv(String name) {
@ -188,8 +190,8 @@ public class SecurityUtils {
}
/**
* Checks the environment variable and returns true if the variable is used in security context. In this case, the
* value should not be displayed in scripts.
* Checks the environment variable and returns true if the variable is used in
* security context. In this case, the value should not be displayed in scripts.
*
* @param name Environment variable to check
* @return true, if this is a secret variable
@ -201,7 +203,8 @@ public class SecurityUtils {
/**
* Configuration for Non-SSL authentication methods.
*
* @return true, if plantUML should allow authentication in plain connections (without encryption).
* @return true, if plantUML should allow authentication in plain connections
* (without encryption).
* @see #SECURITY_ALLOW_NONSSL_AUTH
*/
public static boolean isNonSSLAuthenticationAllowed() {
@ -336,7 +339,8 @@ public class SecurityUtils {
public static boolean existsSecurityCredentials(String userToken) {
SFile securityPath = getSecurityPath();
if (securityPath != null) {
// SFile does not allow access to the security path (to hide the credentials in DSL scripts)
// SFile does not allow access to the security path (to hide the credentials in
// DSL scripts)
File securityFilePath = securityPath.conv();
File userCredentials = new File(securityFilePath, userToken + ".credential");
return userCredentials.exists() && userCredentials.canRead() && !userCredentials.isDirectory()
@ -356,7 +360,8 @@ public class SecurityUtils {
if (userToken != null && checkFileSystemSaveCharactersStrict(userToken) && !NO_CREDENTIALS.equals(userToken)) {
final SFile securityPath = getSecurityPath();
if (securityPath != null) {
// SFile does not allow access to the security path (to hide the credentials in DSL scripts)
// SFile does not allow access to the security path (to hide the credentials in
// DSL scripts)
File securityFilePath = securityPath.conv();
File userCredentials = new File(securityFilePath, userToken + ".credential");
JsonValue jsonValue = loadJson(userCredentials);
@ -367,8 +372,8 @@ public class SecurityUtils {
}
/**
* Checks, if the token of a pathname (filename, ext, directory-name) uses only a very strict set of characters and
* not longer than 64 characters.
* Checks, if the token of a pathname (filename, ext, directory-name) uses only
* a very strict set of characters and not longer than 64 characters.
* <p>
* Only characters from a to Z, Numbers and - are allowed.
*
@ -377,15 +382,16 @@ public class SecurityUtils {
* @see #SECURE_CHARS
*/
private static boolean checkFileSystemSaveCharactersStrict(String pathNameToken) {
return StringUtils.isNotEmpty(pathNameToken)
&& SECURE_CHARS.matcher(pathNameToken).matches() && pathNameToken.length() <= 64;
return StringUtils.isNotEmpty(pathNameToken) && SECURE_CHARS.matcher(pathNameToken).matches()
&& pathNameToken.length() <= 64;
}
/**
* Loads the path to the configured security folder, if existing.
* <p>
* Please note: A SFile referenced to a security folder cannot access the files. The content of the files in the
* security path should never have passed to DSL scripts.
* Please note: A SFile referenced to a security folder cannot access the files.
* The content of the files in the security path should never have passed to DSL
* scripts.
*
* @return SFile folder or null
*/
@ -401,9 +407,9 @@ public class SecurityUtils {
return null;
}
/**
* Loads a file as JSON object. If no file exists or the file is not parsable, the method returns an empty JSON.
* Loads a file as JSON object. If no file exists or the file is not parsable,
* the method returns an empty JSON.
*
* @param jsonFile file path to the JSON file
* @return a Json vale (maybe empty)

View File

@ -912,9 +912,9 @@ public class SvgGraphics {
Objects.requireNonNull(url);
// javascript: security issue
if (SecurityUtils.getJavascriptUnsecure() == false && url.toLowerCase().startsWith("javascript")) {
if (SecurityUtils.ignoreThisLink(url))
return;
}
if (pendingAction.size() > 0) {
closeLink();

View File

@ -173,9 +173,11 @@ public abstract class AbstractCommonUGraphic implements UGraphic {
final public void flushUg() {
}
@Override
public void startUrl(Url url) {
}
@Override
public void closeUrl() {
}

View File

@ -114,10 +114,12 @@ public class UGraphicEps extends AbstractUGraphic<EpsGraphics> implements ClipCo
return ug.getEPSCode();
}
@Override
public void startUrl(Url url) {
getGraphicObject().openLink(url.getUrl());
}
@Override
public void closeUrl() {
getGraphicObject().closeLink();
}

View File

@ -55,6 +55,7 @@ import net.sourceforge.plantuml.anim.AffineTransformation;
import net.sourceforge.plantuml.graphic.StringBounder;
import net.sourceforge.plantuml.png.PngIO;
import net.sourceforge.plantuml.posimo.DotPath;
import net.sourceforge.plantuml.security.SecurityUtils;
import net.sourceforge.plantuml.ugraphic.AbstractCommonUGraphic;
import net.sourceforge.plantuml.ugraphic.AbstractUGraphic;
import net.sourceforge.plantuml.ugraphic.UAntiAliasing;
@ -82,7 +83,7 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
private UAntiAliasing antiAliasing = UAntiAliasing.ANTI_ALIASING_ON;
private/* final */List<Url> urls = new ArrayList<>();
private List<Url> urls = new ArrayList<>();
private Set<Url> allUrls = new HashSet<>();
private final boolean hasAffineTransform;
@ -116,22 +117,22 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
register(dpiFactor);
}
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d, double dpiFactor) {
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
double dpiFactor) {
this(defaultBackground, colorMapper, stringBounder, g2d, dpiFactor, null, 0, 0);
}
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d, double dpiFactor,
AffineTransformation affineTransform, double dx, double dy) {
public UGraphicG2d(HColor defaultBackground, ColorMapper colorMapper, StringBounder stringBounder, Graphics2D g2d,
double dpiFactor, AffineTransformation affineTransform, double dx, double dy) {
super(defaultBackground, colorMapper, stringBounder, g2d);
this.hasAffineTransform = affineTransform != null;
this.dpiFactor = dpiFactor;
if (dpiFactor != 1.0) {
if (dpiFactor != 1.0)
g2d.scale(dpiFactor, dpiFactor);
}
if (this.hasAffineTransform) {
if (dx != 0 || dy != 0) {
if (dx != 0 || dy != 0)
getGraphicObject().transform(AffineTransform.getTranslateInstance(dx, dy));
}
getGraphicObject().transform(affineTransform.getAffineTransform());
}
register(dpiFactor);
@ -176,21 +177,28 @@ public class UGraphicG2d extends AbstractUGraphic<Graphics2D> implements EnsureV
return dpiFactor;
}
@Override
public void startUrl(Url url) {
urls.add(Objects.requireNonNull(url));
allUrls.add(url);
Objects.requireNonNull(url);
// javascript: security issue
if (SecurityUtils.ignoreThisLink(url.getUrl())) {
urls.add(null);
} else {
urls.add(url);
allUrls.add(url);
}
}
@Override
public void closeUrl() {
urls.remove(urls.size() - 1);
}
public void ensureVisible(double x, double y) {
for (Url u : urls) {
if (getClip() == null || getClip().isInside(x, y)) {
for (Url u : urls)
if (u != null && (getClip() == null || getClip().isInside(x, y)))
u.ensureVisible(x, y);
}
}
}
public BufferedImage getBufferedImage() {

View File

@ -89,10 +89,12 @@ public class UGraphicTikz extends AbstractUGraphic<TikzGraphics> implements Clip
registerDriver(UCenteredCharacter.class, new DriverCenteredCharacterTikz2());
}
@Override
public void startUrl(Url url) {
getGraphicObject().openLink(url.getUrl(), url.getTooltip());
}
@Override
public void closeUrl() {
getGraphicObject().closeLink();
}

View File

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