From d8ebbb585709a3118e0c6544af359cd49982df2f Mon Sep 17 00:00:00 2001 From: J-N-K Date: Mon, 16 May 2022 22:33:32 +0200 Subject: [PATCH] Allow sub-directories for icons (#2946) * Allow sub-directories for icons Signed-off-by: Jan N. Klug --- .../ui/icon/internal/CustomIconProvider.java | 25 +++++++++++-------- .../core/ui/icon/internal/IconServlet.java | 6 +++++ .../ui/icon/internal/IconServletTest.java | 16 ++++++------ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/CustomIconProvider.java b/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/CustomIconProvider.java index ff7bd2345e..1b5c811435 100644 --- a/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/CustomIconProvider.java +++ b/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/CustomIconProvider.java @@ -12,13 +12,14 @@ */ package org.openhab.core.ui.icon.internal; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Collections; import java.util.Locale; import java.util.Set; +import java.util.stream.Stream; import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; @@ -46,19 +47,23 @@ public class CustomIconProvider extends AbstractResourceIconProvider { super(i18nProvider); } - private @Nullable File getIconFile(String filename, String iconSetId) { - File folder = new File(OpenHAB.getConfigFolder() + File.separator + "icons" + File.separator + iconSetId); - File file = new File(folder, filename); - return file.exists() ? file : null; + private @Nullable Path getIconFile(String filename, String iconSetId) { + Path folder = Path.of(OpenHAB.getConfigFolder(), "icons", iconSetId); + try (Stream stream = Files.walk(folder)) { + return stream.filter(file -> !Files.isDirectory(file) && filename.equals(file.getFileName().toString())) + .findAny().orElse(null); + } catch (IOException e) { + return null; + } } @Override protected @Nullable InputStream getResource(String iconSetId, String resourceName) { - File file = getIconFile(resourceName, iconSetId); + Path file = getIconFile(resourceName, iconSetId); if (file != null) { try { - return new FileInputStream(file); - } catch (FileNotFoundException e) { + return Files.newInputStream(file); + } catch (IOException e) { return null; } } diff --git a/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/IconServlet.java b/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/IconServlet.java index 9580f938a5..48c715e2fc 100644 --- a/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/IconServlet.java +++ b/bundles/org.openhab.core.ui.icon/src/main/java/org/openhab/core/ui/icon/internal/IconServlet.java @@ -108,6 +108,12 @@ public class IconServlet extends OpenHABServlet { } String category = getCategory(req); + if (category.isEmpty()) { + logger.debug("URI must start with '{}' but is '{}'", SERVLET_NAME, req.getRequestURI()); + resp.sendError(400); + return; + } + String state = getState(req); String iconSetId = getIconSetId(req); diff --git a/bundles/org.openhab.core.ui.icon/src/test/java/org/openhab/core/ui/icon/internal/IconServletTest.java b/bundles/org.openhab.core.ui.icon/src/test/java/org/openhab/core/ui/icon/internal/IconServletTest.java index 5f520ad0d5..09d444c9bd 100644 --- a/bundles/org.openhab.core.ui.icon/src/test/java/org/openhab/core/ui/icon/internal/IconServletTest.java +++ b/bundles/org.openhab.core.ui.icon/src/test/java/org/openhab/core/ui/icon/internal/IconServletTest.java @@ -96,7 +96,7 @@ public class IconServletTest { @Test public void testOldUrlStyle() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/y-34.png"); + when(requestMock.getRequestURI()).thenReturn("/icon/y-34.png"); when(responseMock.getOutputStream()).thenReturn(responseOutputStream); @@ -113,7 +113,7 @@ public class IconServletTest { @Test public void testPriority() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/x"); + when(requestMock.getRequestURI()).thenReturn("/icon/x"); when(requestMock.getParameter(PARAM_FORMAT)).thenReturn("svg"); when(requestMock.getParameter(PARAM_ICONSET)).thenReturn("test"); when(requestMock.getParameter(PARAM_STATE)).thenReturn("34"); @@ -158,7 +158,7 @@ public class IconServletTest { @Test public void testAnyFormatFalse() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/z"); + when(requestMock.getRequestURI()).thenReturn("/icon/z"); when(requestMock.getParameter(PARAM_FORMAT)).thenReturn("svg"); when(requestMock.getParameter(PARAM_ANY_FORMAT)).thenReturn("false"); when(requestMock.getParameter(PARAM_ICONSET)).thenReturn("test"); @@ -180,7 +180,7 @@ public class IconServletTest { @Test public void testAnyFormatSameProviders() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/z"); + when(requestMock.getRequestURI()).thenReturn("/icon/z"); when(requestMock.getParameter(PARAM_FORMAT)).thenReturn("svg"); when(requestMock.getParameter(PARAM_ANY_FORMAT)).thenReturn("true"); when(requestMock.getParameter(PARAM_ICONSET)).thenReturn("test"); @@ -204,7 +204,7 @@ public class IconServletTest { @Test public void testAnyFormatHigherPriorityOtherFormat() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/z"); + when(requestMock.getRequestURI()).thenReturn("/icon/z"); when(requestMock.getParameter(PARAM_FORMAT)).thenReturn("svg"); when(requestMock.getParameter(PARAM_ANY_FORMAT)).thenReturn("true"); when(requestMock.getParameter(PARAM_ICONSET)).thenReturn("test"); @@ -234,7 +234,7 @@ public class IconServletTest { @Test public void testAnyFormatHigherPriorityRequestedFormat() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/z"); + when(requestMock.getRequestURI()).thenReturn("/icon/z"); when(requestMock.getParameter(PARAM_FORMAT)).thenReturn("svg"); when(requestMock.getParameter(PARAM_ANY_FORMAT)).thenReturn("true"); when(requestMock.getParameter(PARAM_ICONSET)).thenReturn("test"); @@ -264,7 +264,7 @@ public class IconServletTest { @Test public void testAnyFormatNoOtherFormat() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/z"); + when(requestMock.getRequestURI()).thenReturn("/icon/z"); when(requestMock.getParameter(PARAM_FORMAT)).thenReturn("svg"); when(requestMock.getParameter(PARAM_ANY_FORMAT)).thenReturn("true"); when(requestMock.getParameter(PARAM_ICONSET)).thenReturn("test"); @@ -288,7 +288,7 @@ public class IconServletTest { @Test public void testAnyFormatNoRequestedFormat() throws ServletException, IOException { - when(requestMock.getRequestURI()).thenReturn("/z"); + when(requestMock.getRequestURI()).thenReturn("/icon/z"); when(requestMock.getParameter(PARAM_FORMAT)).thenReturn("svg"); when(requestMock.getParameter(PARAM_ANY_FORMAT)).thenReturn("true"); when(requestMock.getParameter(PARAM_ICONSET)).thenReturn("test");