diff --git a/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java b/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java index 2f74efdd0..35db6180e 100644 --- a/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java +++ b/server/src/main/java/org/eclipse/openvsx/ExtensionProcessor.java @@ -473,8 +473,9 @@ private String tryGetAssetPath(String type) { return null; } - public @Nullable TempFile getIcon(ExtensionVersion extVersion) throws IOException { + public @Nullable String getIconPath() { var iconPath = tryGetAssetPath(ExtensionQueryResult.ExtensionFile.FILE_ICON); + if (StringUtils.isEmpty(iconPath)) { loadPackageJson(); var iconPathNode = packageJson.get("icon"); @@ -489,6 +490,15 @@ private String tryGetAssetPath(String type) { iconPath = "extension/" + iconPath; } + return iconPath; + } + + public @Nullable TempFile getIcon(ExtensionVersion extVersion) throws IOException { + var iconPath = getIconPath(); + if (iconPath == null) { + return null; + } + var entryFile = ArchiveUtil.readEntry(zipFile, iconPath); if (entryFile == null) { throw new ErrorResultException("Icon " + entryNotFoundMessage(iconPath)); diff --git a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java index d40ad7f18..857c37fa4 100644 --- a/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java +++ b/server/src/main/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandler.java @@ -10,7 +10,6 @@ package org.eclipse.openvsx.publish; import java.io.IOException; -import java.nio.file.Path; import java.time.LocalDateTime; import java.util.List; import java.util.function.Consumer; @@ -65,7 +64,7 @@ public class PublishExtensionVersionHandler { private final ExtensionControlService extensionControl; private final ExtensionScanService scanService; - private final Predicate unsupportedIconExtensions; + private final Predicate unsupportedIconExtensions; public PublishExtensionVersionHandler( PublishingConfig config, @@ -95,7 +94,7 @@ public PublishExtensionVersionHandler( return false; } - var fileExtension = FilenameUtils.getExtension(path.toString()); + var fileExtension = FilenameUtils.getExtension(path); return config.getUnsupportedIconFormats().stream().anyMatch(ext -> ext.equalsIgnoreCase(fileExtension)); }; } @@ -115,7 +114,7 @@ public ExtensionVersion createExtensionVersion(ExtensionProcessor processor, Per .map(id -> parseExtensionId(id, "extensionDependencies")) .toList(); - if(!parsedDependencies.isEmpty()) { + if (!parsedDependencies.isEmpty()) { checkDependencies(parsedDependencies); } bundledExtensions.forEach(id -> parseExtensionId(id, "extensionPack")); @@ -123,7 +122,7 @@ public ExtensionVersion createExtensionVersion(ExtensionProcessor processor, Per extVersion.setDependencies(dependencies); extVersion.setBundledExtensions(bundledExtensions); - if(integrityService.isEnabled()) { + if (integrityService.isEnabled()) { extVersion.setSignatureKeyPair(repositories.findActiveKeyPair()); } @@ -178,7 +177,8 @@ private ExtensionVersion createExtensionVersion(ExtensionProcessor processor, Us extVersion.setExtension(extension); validateLicense(processor, extVersion); - validateIcon(processor, extVersion); + validateIcon(processor); + validateFileResources(processor, extVersion); validateMetadata(extVersion); entityManager.persist(extVersion); return extVersion; @@ -221,13 +221,22 @@ private void checkLicense(ExtensionVersion extVersion, TempFile licenseFile) { } } - private void validateIcon(ExtensionProcessor processor, ExtensionVersion extVersion) { - try (var iconFile = processor.getIcon(extVersion)) { - if (iconFile != null && unsupportedIconExtensions.test(iconFile.getPath())) { - throw new ErrorResultException("This extension cannot be accepted as it uses an unsupported icon format."); - } - } catch (IOException e) { - throw new ServerErrorException("Failed to read icon file", e); + private void validateIcon(ExtensionProcessor processor) { + var iconPath = processor.getIconPath(); + if (iconPath != null && unsupportedIconExtensions.test(iconPath)) { + throw new ErrorResultException("This extension cannot be accepted as it uses an unsupported icon format."); + } + } + + private void validateFileResources(ExtensionProcessor processor, ExtensionVersion extVersion) { + try { + // Validate that all file resources are readable/accessible during synchronous publishing + // to avoid failing during async publishing and report errors directly back to publishers. + // This creates unnecessary temp files, however these are usually small and thus it is + // acceptable in this case. + processor.getFileResources(extVersion, _ -> {}); + } catch (ErrorResultException exc) { + throw new ErrorResultException("Validation failed: " + exc.getMessage()); } } diff --git a/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java b/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java index 4eb3761ee..0ca67f9c8 100644 --- a/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java +++ b/server/src/test/java/org/eclipse/openvsx/publish/PublishExtensionVersionHandlerTest.java @@ -18,7 +18,6 @@ import static org.mockito.Mockito.when; import java.io.IOException; -import java.nio.file.Path; import java.time.LocalDateTime; import java.util.Collections; import java.util.List; @@ -35,7 +34,6 @@ import org.eclipse.openvsx.repositories.RepositoryService; import org.eclipse.openvsx.scanning.ExtensionScanService; import org.eclipse.openvsx.util.ErrorResultException; -import org.eclipse.openvsx.util.TempFile; import org.jobrunr.scheduling.JobRequestScheduler; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -207,7 +205,7 @@ private ExtensionVersion mockExtensionVersion(String namespace, String name, Str when(processor.getExtensionName()).thenReturn(name); when(processor.getVersion()).thenReturn(version); if (iconPath != null) { - when(processor.getIcon(ArgumentMatchers.any())).thenReturn(new TempFile(Path.of(iconPath))); + when(processor.getIconPath()).thenReturn(iconPath); } var ev = new ExtensionVersion();