mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 06:50:54 +07:00
WEB-52274 Support non-base64 encoded image URLs
(cherry picked from commit 3d5276cb62a60589895686370a2da160343912cb) IJ-CR-148627 GitOrigin-RevId: 91318d4c76703ca673b364b77c181a706441e6b6
This commit is contained in:
committed by
intellij-monorepo-bot
parent
eae71268ca
commit
6a7ed7a79a
@@ -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 = Regex("^(vbscript|javascript|file|data):", RegexOption.IGNORE_CASE)
|
||||||
private val UNSAFE_LINK_REGEX_IMAGE = Regex("^(vbscript|javascript|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 */
|
/* 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 {
|
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())
|
!(if (isImage) UNSAFE_LINK_REGEX_IMAGE else UNSAFE_LINK_REGEX).containsMatchIn(s.trim()) || ALLOWED_DATA_LINK_REGEX.containsMatchIn(s.trim())
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.intellij.util.ui;
|
|||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.ui.svg.SvgImageDecoder;
|
import com.intellij.ui.svg.SvgImageDecoder;
|
||||||
|
import com.intellij.util.io.URLUtil;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -19,6 +20,7 @@ import java.net.MalformedURLException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.net.URLStreamHandler;
|
import java.net.URLStreamHandler;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -66,8 +68,8 @@ public final class JBImageToolkit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiStatus.Internal
|
@ApiStatus.Internal
|
||||||
public static URL tryBuildBase64Url(@NotNull String url) throws MalformedURLException {
|
public static URL tryBuildDataImageUrl(@NotNull String url) throws MalformedURLException {
|
||||||
if (url.startsWith("data:image") && url.contains("base64")) {
|
if (url.startsWith("data:image/") && url.contains(",")) {
|
||||||
return new URL(null, url, JBImageToolkit.dataImageStreamUrlHandler);
|
return new URL(null, url, JBImageToolkit.dataImageStreamUrlHandler);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -87,8 +89,10 @@ public final class JBImageToolkit {
|
|||||||
return SvgImageDecoder.Companion.detect(source, bufferedStream, -1, -1);
|
return SvgImageDecoder.Companion.detect(source, bufferedStream, -1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JBImageToolkit() {}
|
private JBImageToolkit() { }
|
||||||
|
|
||||||
private static final URLStreamHandler dataImageStreamUrlHandler = new DataImageURLStreamHandler();
|
private static final URLStreamHandler dataImageStreamUrlHandler = new DataImageURLStreamHandler();
|
||||||
|
|
||||||
private static class DataImageURLStreamHandler extends URLStreamHandler {
|
private static class DataImageURLStreamHandler extends URLStreamHandler {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -105,9 +109,12 @@ public final class JBImageToolkit {
|
|||||||
connect(); // Mimics the semantics of an actual URL connection.
|
connect(); // Mimics the semantics of an actual URL connection.
|
||||||
var parts = StringUtil.split(u.toString(), ",");
|
var parts = StringUtil.split(u.toString(), ",");
|
||||||
if (parts.size() == 2) {
|
if (parts.size() == 2) {
|
||||||
|
var isBase64 = parts.get(0).endsWith(";base64");
|
||||||
var encodedImage = parts.get(1);
|
var encodedImage = parts.get(1);
|
||||||
return new ByteArrayInputStream(Base64.getDecoder().decode(encodedImage));
|
return new ByteArrayInputStream(isBase64 ? Base64.getDecoder().decode(encodedImage)
|
||||||
} else {
|
: URLUtil.decode(encodedImage).getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
else {
|
||||||
throw new IOException("Malformed data url: " + u);
|
throw new IOException("Malformed data url: " + u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import javax.swing.text.Element
|
|||||||
import javax.swing.text.html.HTML
|
import javax.swing.text.html.HTML
|
||||||
import javax.swing.text.html.ImageView
|
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? =
|
override fun getImageURL(): URL? =
|
||||||
element.attributes.getAttribute(HTML.Attribute.SRC).asSafely<String>()?.let {
|
element.attributes.getAttribute(HTML.Attribute.SRC).asSafely<String>()?.let {
|
||||||
JBImageToolkit.tryBuildBase64Url(it)
|
JBImageToolkit.tryBuildDataImageUrl(it)
|
||||||
} ?: super.getImageURL()
|
} ?: super.getImageURL()
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,7 @@ import javax.swing.text.FlowView
|
|||||||
import javax.swing.text.View
|
import javax.swing.text.View
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
internal class FitToWidthImageView(element: Element) : Base64ImageView(element) {
|
internal class FitToWidthImageView(element: Element) : DataUrlImageView(element) {
|
||||||
private var myAvailableWidth = 0
|
private var myAvailableWidth = 0
|
||||||
|
|
||||||
override fun getLoadingImageIcon(): Icon =
|
override fun getLoadingImageIcon(): Icon =
|
||||||
|
|||||||
@@ -13,9 +13,8 @@ import java.awt.Shape
|
|||||||
import java.awt.image.BufferedImage
|
import java.awt.image.BufferedImage
|
||||||
import javax.swing.Icon
|
import javax.swing.Icon
|
||||||
import javax.swing.text.Element
|
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?
|
private val scaleContext: ScaleContext?
|
||||||
get() = container?.takeIf(StartupUiUtil::isJreHiDPI)?.let(ScaleContext::create)
|
get() = container?.takeIf(StartupUiUtil::isJreHiDPI)?.let(ScaleContext::create)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user