2828import org .eclipse .openvsx .eclipse .EclipseService ;
2929import org .eclipse .openvsx .entities .*;
3030import org .eclipse .openvsx .json .*;
31+ import org .eclipse .openvsx .publish .ExtensionVersionIntegrityService ;
3132import org .eclipse .openvsx .repositories .RepositoryService ;
3233import org .eclipse .openvsx .search .ExtensionSearch ;
3334import org .eclipse .openvsx .search .ISearchService ;
@@ -82,6 +83,9 @@ public class LocalRegistryService implements IExtensionRegistry {
8283 @ Autowired
8384 CacheService cache ;
8485
86+ @ Autowired
87+ ExtensionVersionIntegrityService integrityService ;
88+
8589 @ Override
8690 public NamespaceJson getNamespace (String namespaceName ) {
8791 var namespace = repositories .findNamespace (namespaceName );
@@ -130,7 +134,7 @@ private Map<String, String> getDownloads(Extension extension, String targetPlatf
130134 var download = files != null ? files .get (DOWNLOAD ) : null ;
131135 if (download == null ) {
132136 var e = ev .getExtension ();
133- logger .warn ("Could not find download for: {}.{}-{}@{} " , e . getNamespace (). getName (), e . getName (), ev . getVersion (), ev . getTargetPlatform ( ));
137+ logger .warn ("Could not find download for: {}" , NamingUtil . toLogFormat ( ev ));
134138 return null ;
135139 } else {
136140 return new AbstractMap .SimpleEntry <>(ev .getTargetPlatform (), download );
@@ -182,7 +186,11 @@ public ResponseEntity<byte[]> getFile(String namespace, String extensionName, St
182186 }
183187
184188 public boolean isType (String fileName ){
185- var expectedTypes = List .of (MANIFEST , README , LICENSE , ICON , DOWNLOAD , DOWNLOAD_SHA256 , CHANGELOG , VSIXMANIFEST );
189+ var expectedTypes = new ArrayList <>(List .of (MANIFEST , README , LICENSE , ICON , DOWNLOAD , DOWNLOAD_SHA256 , CHANGELOG , VSIXMANIFEST ));
190+ if (integrityService .isEnabled ()) {
191+ expectedTypes .add (DOWNLOAD_SIG );
192+ }
193+
186194 return expectedTypes .stream ().anyMatch (fileName ::equalsIgnoreCase );
187195 }
188196
@@ -431,10 +439,26 @@ private SearchEntryJson toSearchEntryJson(Extension extension) {
431439 var extVersion = versions .getLatest (extension , null , false , true );
432440 var entry = extVersion .toSearchEntryJson ();
433441 entry .url = createApiUrl (serverUrl , "api" , entry .namespace , entry .name );
434- entry .files = storageUtil .getFileUrls (extVersion , serverUrl , DOWNLOAD , DOWNLOAD_SHA256 , ICON );
442+ entry .files = storageUtil .getFileUrls (extVersion , serverUrl , withFileTypes (DOWNLOAD , ICON ));
443+ if (entry .files .containsKey (DOWNLOAD_SIG )) {
444+ entry .files .put (PUBLIC_KEY , UrlUtil .getPublicKeyUrl (extVersion ));
445+ }
446+
435447 return entry ;
436448 }
437449
450+ private String [] withFileTypes (String ... types ) {
451+ var typesList = new ArrayList <>(List .of (types ));
452+ if (typesList .contains (DOWNLOAD )) {
453+ typesList .add (DOWNLOAD_SHA256 );
454+ if (integrityService .isEnabled ()) {
455+ typesList .add (DOWNLOAD_SIG );
456+ }
457+ }
458+
459+ return typesList .toArray (String []::new );
460+ }
461+
438462 @ Override
439463 public ResponseEntity <byte []> getNamespaceLogo (String namespaceName , String fileName ) {
440464 if (fileName == null ) {
@@ -515,7 +539,7 @@ private Map<Long, List<FileResource>> getFileResources(List<ExtensionVersion> ex
515539 return Collections .emptyMap ();
516540 }
517541
518- var fileTypes = List .of (DOWNLOAD , DOWNLOAD_SHA256 , MANIFEST , ICON , README , LICENSE , CHANGELOG , VSIXMANIFEST );
542+ var fileTypes = List .of (withFileTypes ( DOWNLOAD , MANIFEST , ICON , README , LICENSE , CHANGELOG , VSIXMANIFEST ) );
519543 var extensionVersionIds = extensionVersions .stream ()
520544 .map (ExtensionVersion ::getId )
521545 .collect (Collectors .toSet ());
@@ -674,8 +698,7 @@ public ExtensionJson publish(InputStream content, String tokenValue) throws Erro
674698 var semver = extVersion .getSemanticVersion ();
675699 var newVersion = String .join ("." , String .valueOf (semver .getMajor ()), String .valueOf (semver .getMinor () + 1 ), "0" );
676700
677- json .warning = "A " + existingRelease + " already exists for " +
678- extension .getNamespace ().getName () + "." + extension .getName () + "-" + extVersion .getVersion () + ".\n " +
701+ json .warning = "A " + existingRelease + " already exists for " + NamingUtil .toLogFormat (extension .getNamespace ().getName (), extension .getName (), extVersion .getVersion ()) + ".\n " +
679702 "To prevent update conflicts, we recommend that this " + thisRelease + " uses " + newVersion + " as its version instead." ;
680703 }
681704
@@ -690,7 +713,8 @@ public ResultJson postReview(ReviewJson review, String namespace, String extensi
690713 }
691714 var extension = repositories .findExtension (extensionName , namespace );
692715 if (extension == null || !extension .isActive ()) {
693- return ResultJson .error ("Extension not found: " + namespace + "." + extensionName );
716+ var extensionId = NamingUtil .toExtensionId (namespace , extensionName );
717+ return ResultJson .error ("Extension not found: " + extensionId );
694718 }
695719 var activeReviews = repositories .findActiveReviews (extension , user );
696720 if (!activeReviews .isEmpty ()) {
@@ -711,7 +735,7 @@ public ResultJson postReview(ReviewJson review, String namespace, String extensi
711735 search .updateSearchEntry (extension );
712736 cache .evictExtensionJsons (extension );
713737 cache .evictLatestExtensionVersion (extension );
714- return ResultJson .success ("Added review for " + extension . getNamespace (). getName () + "." + extension . getName ( ));
738+ return ResultJson .success ("Added review for " + NamingUtil . toExtensionId ( extension ));
715739 }
716740
717741 @ Transactional (rollbackOn = ResponseStatusException .class )
@@ -722,7 +746,7 @@ public ResultJson deleteReview(String namespace, String extensionName) {
722746 }
723747 var extension = repositories .findExtension (extensionName , namespace );
724748 if (extension == null || !extension .isActive ()) {
725- return ResultJson .error ("Extension not found: " + namespace + "." + extensionName );
749+ return ResultJson .error ("Extension not found: " + NamingUtil . toExtensionId ( namespace , extensionName ) );
726750 }
727751 var activeReviews = repositories .findActiveReviews (extension , user );
728752 if (activeReviews .isEmpty ()) {
@@ -738,7 +762,7 @@ public ResultJson deleteReview(String namespace, String extensionName) {
738762 search .updateSearchEntry (extension );
739763 cache .evictExtensionJsons (extension );
740764 cache .evictLatestExtensionVersion (extension );
741- return ResultJson .success ("Deleted review for " + extension . getNamespace (). getName () + "." + extension . getName ( ));
765+ return ResultJson .success ("Deleted review for " + NamingUtil . toExtensionId ( extension ));
742766 }
743767
744768 private Extension getExtension (SearchHit <ExtensionSearch > searchHit ) {
@@ -776,8 +800,14 @@ private List<SearchEntryJson> toSearchEntries(SearchHits<ExtensionSearch> search
776800 })
777801 .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue ));
778802
779- var fileUrls = storageUtil .getFileUrls (latestVersions .values (), serverUrl , DOWNLOAD , DOWNLOAD_SHA256 , ICON );
780- searchEntries .forEach ((extensionId , searchEntry ) -> searchEntry .files = fileUrls .get (latestVersions .get (extensionId ).getId ()));
803+ var fileUrls = storageUtil .getFileUrls (latestVersions .values (), serverUrl , withFileTypes (DOWNLOAD , ICON ));
804+ searchEntries .forEach ((extensionId , searchEntry ) -> {
805+ var extVersion = latestVersions .get (extensionId );
806+ searchEntry .files = fileUrls .get (extVersion .getId ());
807+ if (searchEntry .files .containsKey (DOWNLOAD_SIG )) {
808+ searchEntry .files .put (PUBLIC_KEY , UrlUtil .getPublicKeyUrl (extVersion ));
809+ }
810+ });
781811 if (options .includeAllVersions ) {
782812 var allActiveVersions = repositories .findActiveVersions (extensions ).stream ()
783813 .sorted (ExtensionVersion .SORT_COMPARATOR )
@@ -867,8 +897,11 @@ public ExtensionJson toExtensionVersionJson(ExtensionVersion extVersion, String
867897 .forEach (e -> json .allVersions .put (e .getKey (), e .getValue ()));
868898 }
869899
870- var fileUrls = storageUtil .getFileUrls (List .of (extVersion ), serverUrl , DOWNLOAD , DOWNLOAD_SHA256 , MANIFEST , ICON , README , LICENSE , CHANGELOG , VSIXMANIFEST );
900+ var fileUrls = storageUtil .getFileUrls (List .of (extVersion ), serverUrl , withFileTypes ( DOWNLOAD , MANIFEST , ICON , README , LICENSE , CHANGELOG , VSIXMANIFEST ) );
871901 json .files = fileUrls .get (extVersion .getId ());
902+ if (json .files .containsKey (DOWNLOAD_SIG )) {
903+ json .files .put (PUBLIC_KEY , UrlUtil .getPublicKeyUrl (extVersion ));
904+ }
872905 if (json .dependencies != null ) {
873906 json .dependencies .forEach (ref -> {
874907 ref .url = createApiUrl (serverUrl , "api" , ref .namespace , ref .extension );
@@ -928,12 +961,15 @@ public ExtensionJson toExtensionVersionJson(
928961 json .allVersions .put (version , createApiUrl (versionBaseUrl , version ));
929962 }
930963
931- json .files = Maps .newLinkedHashMapWithExpectedSize (6 );
964+ json .files = Maps .newLinkedHashMapWithExpectedSize (8 );
932965 var fileBaseUrl = UrlUtil .createApiFileBaseUrl (serverUrl , json .namespace , json .name , json .targetPlatform , json .version );
933966 for (var resource : resources ) {
934967 var fileUrl = UrlUtil .createApiFileUrl (fileBaseUrl , resource .getName ());
935968 json .files .put (resource .getType (), fileUrl );
936969 }
970+ if (json .files .containsKey (DOWNLOAD_SIG )) {
971+ json .files .put (PUBLIC_KEY , UrlUtil .getPublicKeyUrl (extVersion ));
972+ }
937973
938974 if (json .dependencies != null ) {
939975 json .dependencies .forEach (ref -> {
@@ -1001,12 +1037,15 @@ public ExtensionJson toExtensionVersionJsonV2(
10011037 }
10021038 }
10031039
1004- json .files = Maps .newLinkedHashMapWithExpectedSize (6 );
1040+ json .files = Maps .newLinkedHashMapWithExpectedSize (8 );
10051041 var fileBaseUrl = UrlUtil .createApiFileBaseUrl (serverUrl , json .namespace , json .name , json .targetPlatform , json .version );
10061042 for (var resource : resources ) {
10071043 var fileUrl = UrlUtil .createApiFileUrl (fileBaseUrl , resource .getName ());
10081044 json .files .put (resource .getType (), fileUrl );
10091045 }
1046+ if (json .files .containsKey (DOWNLOAD_SIG )) {
1047+ json .files .put (PUBLIC_KEY , UrlUtil .getPublicKeyUrl (extVersion ));
1048+ }
10101049
10111050 if (json .dependencies != null ) {
10121051 json .dependencies .forEach (ref -> {
@@ -1051,4 +1090,13 @@ private boolean isVerified(ExtensionVersion extVersion, Map<Long, List<Namespace
10511090 return memberships .stream ().anyMatch (m -> m .getRole ().equalsIgnoreCase (NamespaceMembership .ROLE_OWNER ))
10521091 && memberships .stream ().anyMatch (m -> m .getUser ().getId () == user .getId ());
10531092 }
1093+
1094+ public String getPublicKey (String publicId ) {
1095+ var keyPair = repositories .findKeyPair (publicId );
1096+ if (keyPair == null ) {
1097+ throw new NotFoundException ();
1098+ }
1099+
1100+ return keyPair .getPublicKeyText ();
1101+ }
10541102}
0 commit comments