Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 64 additions & 19 deletions server/src/main/java/org/eclipse/openvsx/RegistryAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,12 @@ public ResponseEntity<NamespaceJson> getNamespace(
// Try the next registry
}
}

var json = NamespaceJson.error("Namespace not found: " + namespace);
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping(
Expand Down Expand Up @@ -135,7 +139,10 @@ public ResponseEntity<ResultJson> verifyToken(
return ResponseEntity.ok(local.verifyToken(namespace, token));
} catch (NotFoundException exc) {
var json = ResultJson.error("Namespace not found: " + namespace);
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
} catch (ErrorResultException exc) {
return exc.toResponseEntity(ResultJson.class);
}
Expand Down Expand Up @@ -163,14 +170,17 @@ public ResponseEntity<NamespaceDetailsJson> getNamespaceDetails(
for (var registry : getRegistries()) {
try {
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().cachePublic())
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic())
.body(registry.getNamespaceDetails(namespace));
} catch (NotFoundException exc) {
// Try the next registry
}
}
var json = NamespaceDetailsJson.error(namespaceNotFoundMessage(namespace));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

private String extensionNotFoundMessage(String extension) {
Expand Down Expand Up @@ -221,7 +231,10 @@ public ResponseEntity<StreamingResponseBody> getNamespaceLogo(
}
}

throw new NotFoundException();
return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
}

@GetMapping(
Expand All @@ -248,14 +261,17 @@ public ResponseEntity<ExtensionJson> getExtension(
for (var registry : getRegistries()) {
try {
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().cachePublic())
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic())
.body(registry.getExtension(namespace, extension, null));
} catch (NotFoundException exc) {
// Try the next registry
}
}
var json = ExtensionJson.error(extensionNotFoundMessage(NamingUtil.toExtensionId(namespace, extension)));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping(
Expand Down Expand Up @@ -302,7 +318,10 @@ public ResponseEntity<ExtensionJson> getExtension(
}
}
var json = ExtensionJson.error(extensionNotFoundMessage(NamingUtil.toLogFormat(namespace, extension, targetPlatform.toString(), null)));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping(
Expand Down Expand Up @@ -331,14 +350,17 @@ public ResponseEntity<ExtensionJson> getExtension(
for (var registry : getRegistries()) {
try {
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().cachePublic())
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic())
.body(registry.getExtension(namespace, extension, null, version));
} catch (NotFoundException exc) {
// Try the next registry
}
}
var json = ExtensionJson.error(extensionNotFoundMessage(NamingUtil.toLogFormat(namespace, extension, version)));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping(
Expand Down Expand Up @@ -387,7 +409,10 @@ public ResponseEntity<ExtensionJson> getExtension(
}
}
var json = ExtensionJson.error(extensionNotFoundMessage(NamingUtil.toLogFormat(namespace, extension, targetPlatform, version)));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping(
Expand Down Expand Up @@ -482,7 +507,10 @@ private ResponseEntity<VersionsJson> handleGetVersions(String namespace, String
}
}
var json = VersionsJson.error(extensionNotFoundMessage(NamingUtil.toLogFormat(namespace, extension, targetPlatform)));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping(
Expand Down Expand Up @@ -577,7 +605,10 @@ private ResponseEntity<VersionReferencesJson> handleGetVersionReferences(String
}
}
var json = VersionReferencesJson.error(extensionNotFoundMessage(NamingUtil.toLogFormat(namespace, extension, targetPlatform)));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping("/api/{namespace}/{extension}/{version:" + VERSION_PATH_PARAM_REGEX + "}/file/**")
Expand Down Expand Up @@ -619,7 +650,11 @@ public ResponseEntity<StreamingResponseBody> getFile(
// Try the next registry
}
}
throw new NotFoundException();

return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
}

@GetMapping("/api/{namespace}/{extension}/{targetPlatform:" + TargetPlatform.NAMES_PATH_PARAM_REGEX + "}/{version:" + VERSION_PATH_PARAM_REGEX + "}/file/**")
Expand Down Expand Up @@ -674,7 +709,11 @@ public ResponseEntity<StreamingResponseBody> getFile(
// Try the next registry
}
}
throw new NotFoundException();

return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
}

@GetMapping(
Expand All @@ -701,14 +740,17 @@ public ResponseEntity<ReviewListJson> getReviews(
for (var registry : getRegistries()) {
try {
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().cachePublic())
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic())
.body(registry.getReviews(namespace, extension));
} catch (NotFoundException exc) {
// Try the next registry
}
}
var json = ReviewListJson.error(extensionNotFoundMessage(NamingUtil.toExtensionId(namespace, extension)));
return new ResponseEntity<>(json, HttpStatus.NOT_FOUND);
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.body(json);
}

@GetMapping(
Expand Down Expand Up @@ -805,7 +847,7 @@ public ResponseEntity<SearchResultJson> search(
result.setTotalSize(resultSize);
result.setExtensions(resultExtensions);
return ResponseEntity.ok()
.cacheControl(CacheControl.noCache().cachePublic())
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic())
.body(result);
}

Expand Down Expand Up @@ -1388,7 +1430,10 @@ public ResponseEntity<String> getPublicKey(
}
}

return ResponseEntity.notFound().build();
return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
}

@GetMapping(path = "/api/version", produces = MediaType.APPLICATION_JSON_VALUE)
Expand Down
53 changes: 36 additions & 17 deletions server/src/main/java/org/eclipse/openvsx/adapter/VSCodeAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,14 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.net.URI;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static org.eclipse.openvsx.adapter.ExtensionQueryParam.*;
import static org.eclipse.openvsx.adapter.ExtensionQueryResult.ExtensionFile.*;
import static org.eclipse.openvsx.util.TargetPlatform.*;

Expand Down Expand Up @@ -165,7 +162,11 @@
// Try the next registry
}
}
return ResponseEntity.notFound().build();

return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
} catch (ErrorResultException ex) {
logger.error(ex.getMessage());
return ResponseEntity.internalServerError().build();
Expand Down Expand Up @@ -195,11 +196,10 @@
description = "The specified item could not be found",
content = @Content()
)
public ModelAndView getItemUrl(
public ResponseEntity<String> getItemUrl(
@RequestParam
@Parameter(description = "Identifier in the format {publisher}.{name}", example = "foo.bar")
String itemName,
ModelMap model
String itemName
) {
var dotIndex = itemName.indexOf('.');
if (dotIndex < 0) {
Expand All @@ -211,13 +211,19 @@
for (var service : getVSCodeServices()) {
try {
var itemUrl = service.getItemUrl(namespace, extension);
return new ModelAndView("redirect:" + itemUrl, model);
return ResponseEntity.status(HttpStatus.FOUND)
.cacheControl(CacheControl.maxAge(1, TimeUnit.DAYS).cachePublic())
.location(URI.create(itemUrl))
.build();

Check failure

Code scanning / CodeQL

Cross-site scripting High

Cross-site scripting vulnerability due to a
user-provided value
.
Comment thread
netomi marked this conversation as resolved.
Dismissed
} catch (NotFoundException exc) {
// Try the next registry
}
}

return new ModelAndView(null, HttpStatus.NOT_FOUND);
return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
}

@GetMapping("/vscode/gallery/publishers/{namespaceName}/vsextensions/{extensionName}/{version}/vspackage")
Expand All @@ -243,7 +249,7 @@
description = "The specified package could not be found",
content = @Content()
)
public ModelAndView download(
public ResponseEntity<String> download(
@PathVariable @Parameter(description = "Extension namespace", example = "JFrog") String namespaceName,
@PathVariable @Parameter(description = "Extension name", example = "jfrog-vscode-extension") String extensionName,
@PathVariable @Parameter(description = "Extension version", example = "2.11.7") String version,
Expand All @@ -259,19 +265,24 @@
NAME_WEB, NAME_UNIVERSAL
})
)
String targetPlatform,
ModelMap model
String targetPlatform
) {
for (var service : getVSCodeServices()) {
try {
var downloadUrl = service.download(namespaceName, extensionName, version, targetPlatform);
return new ModelAndView("redirect:" + downloadUrl, model);
return ResponseEntity.status(HttpStatus.FOUND)
.cacheControl(CacheControl.maxAge(1, TimeUnit.DAYS).cachePublic())
.location(URI.create(downloadUrl))
.build();

Check failure

Code scanning / CodeQL

Cross-site scripting High

Cross-site scripting vulnerability due to a
user-provided value
.
Cross-site scripting vulnerability due to a
user-provided value
.
Cross-site scripting vulnerability due to a
user-provided value
.
Comment thread
netomi marked this conversation as resolved.
Dismissed
} catch (NotFoundException exc) {
// Try the next registry
}
}

return new ModelAndView(null, HttpStatus.NOT_FOUND);
return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
}

@Observed
Expand Down Expand Up @@ -321,7 +332,11 @@
// Try the next registry
}
}
return ResponseEntity.notFound().build();

return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
} catch (ErrorResultException ex) {
logger.error(ex.getMessage());
return ResponseEntity.internalServerError().build();
Expand Down Expand Up @@ -358,7 +373,11 @@
// Try the next registry
}
}
return ResponseEntity.notFound().build();

return ResponseEntity
.notFound()
.cacheControl(CacheControl.maxAge(10, TimeUnit.MINUTES).cachePublic().mustRevalidate())
.build();
} catch (ErrorResultException ex) {
logger.error(ex.getMessage());
return ResponseEntity.internalServerError().build();
Expand Down