WEB-52274 Support non-base64 encoded image URLs

(cherry picked from commit 3d5276cb62a60589895686370a2da160343912cb)

IJ-CR-148627

GitOrigin-RevId: 91318d4c76703ca673b364b77c181a706441e6b6
This commit is contained in:
Piotr Tomiak
2024-11-05 17:18:23 +01:00
committed by intellij-monorepo-bot
parent eae71268ca
commit 6a7ed7a79a
5 changed files with 17 additions and 11 deletions

View File

@@ -8,7 +8,7 @@ import org.intellij.markdown.html.LinkGeneratingProvider
private val UNSAFE_LINK_REGEX = Regex("^(vbscript|javascript|file|data):", RegexOption.IGNORE_CASE)
private val UNSAFE_LINK_REGEX_IMAGE = Regex("^(vbscript|javascript|data):", RegexOption.IGNORE_CASE)
/* We need to support svg for documentation rendering */
private val ALLOWED_DATA_LINK_REGEX = Regex("^data:image/(gif|png|jpeg|webp|svg)(\\+[a-z0-9A-Z]*)?;", RegexOption.IGNORE_CASE)
private val ALLOWED_DATA_LINK_REGEX = Regex("^data:image/(gif|png|jpeg|webp|svg)[+;=a-z0-9A-Z]*,", RegexOption.IGNORE_CASE)
fun makeXssSafeDestination(s: CharSequence, isImage: Boolean): CharSequence = s.takeIf {
!(if (isImage) UNSAFE_LINK_REGEX_IMAGE else UNSAFE_LINK_REGEX).containsMatchIn(s.trim()) || ALLOWED_DATA_LINK_REGEX.containsMatchIn(s.trim())

View File

@@ -3,6 +3,7 @@ package com.intellij.util.ui;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.ui.svg.SvgImageDecoder;
import com.intellij.util.io.URLUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -19,6 +20,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.function.Function;
@@ -66,8 +68,8 @@ public final class JBImageToolkit {
}
@ApiStatus.Internal
public static URL tryBuildBase64Url(@NotNull String url) throws MalformedURLException {
if (url.startsWith("data:image") && url.contains("base64")) {
public static URL tryBuildDataImageUrl(@NotNull String url) throws MalformedURLException {
if (url.startsWith("data:image/") && url.contains(",")) {
return new URL(null, url, JBImageToolkit.dataImageStreamUrlHandler);
}
return null;
@@ -87,8 +89,10 @@ public final class JBImageToolkit {
return SvgImageDecoder.Companion.detect(source, bufferedStream, -1, -1);
}
private JBImageToolkit() {}
private JBImageToolkit() { }
private static final URLStreamHandler dataImageStreamUrlHandler = new DataImageURLStreamHandler();
private static class DataImageURLStreamHandler extends URLStreamHandler {
@Override
@@ -105,9 +109,12 @@ public final class JBImageToolkit {
connect(); // Mimics the semantics of an actual URL connection.
var parts = StringUtil.split(u.toString(), ",");
if (parts.size() == 2) {
var isBase64 = parts.get(0).endsWith(";base64");
var encodedImage = parts.get(1);
return new ByteArrayInputStream(Base64.getDecoder().decode(encodedImage));
} else {
return new ByteArrayInputStream(isBase64 ? Base64.getDecoder().decode(encodedImage)
: URLUtil.decode(encodedImage).getBytes(StandardCharsets.UTF_8));
}
else {
throw new IOException("Malformed data url: " + u);
}
}

View File

@@ -10,11 +10,11 @@ import javax.swing.text.Element
import javax.swing.text.html.HTML
import javax.swing.text.html.ImageView
internal open class Base64ImageView(elem: Element?) : ImageView(elem) {
internal open class DataUrlImageView(elem: Element?) : ImageView(elem) {
override fun getImageURL(): URL? =
element.attributes.getAttribute(HTML.Attribute.SRC).asSafely<String>()?.let {
JBImageToolkit.tryBuildBase64Url(it)
JBImageToolkit.tryBuildDataImageUrl(it)
} ?: super.getImageURL()
}

View File

@@ -11,7 +11,7 @@ import javax.swing.text.FlowView
import javax.swing.text.View
import kotlin.math.max
internal class FitToWidthImageView(element: Element) : Base64ImageView(element) {
internal class FitToWidthImageView(element: Element) : DataUrlImageView(element) {
private var myAvailableWidth = 0
override fun getLoadingImageIcon(): Icon =

View File

@@ -13,9 +13,8 @@ import java.awt.Shape
import java.awt.image.BufferedImage
import javax.swing.Icon
import javax.swing.text.Element
import javax.swing.text.html.ImageView
internal class HiDpiScalingImageView(elem: Element) : Base64ImageView(elem) {
internal class HiDpiScalingImageView(elem: Element) : DataUrlImageView(elem) {
private val scaleContext: ScaleContext?
get() = container?.takeIf(StartupUiUtil::isJreHiDPI)?.let(ScaleContext::create)