commit c2ad3fea0544a9d3619c1ad9ebd5cc6e94d52ac5 Author: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Sun Apr 26 21:28:28 2026 +0200 Basis import diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..df00c07 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/sonarlint.xml b/.idea/sonarlint.xml new file mode 100644 index 0000000..5b670f2 --- /dev/null +++ b/.idea/sonarlint.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..2b63946 --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..66fe871 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1777206490693 + + + + + + + + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/RegistrationsBaseUrlService.java + 44 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/ReadmeUriTemplateService.java + 41 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/presentation/Dustspeck2HttpHandler.java + 50 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityInfoService.java + 41 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/SearchQueryService.java + 40 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VersionPageService.java + 43 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VersionPageService.java + 30 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VersionPageService.java + 33 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VersionPageService.java + 35 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/PackageBaseAddressService.java + 32 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/PackageBaseAddressService.java + 35 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/PackageBaseAddressService.java + 37 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/PackageBaseAddressService.java + 45 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityBaseService.java + 43 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java + 30 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java + 33 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java + 35 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java + 43 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java + 53 + + + file://$PROJECT_DIR$/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityInfoService.java + 31 + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..167301d --- /dev/null +++ b/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + moe.yo3explorer + dustspeck2 + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + + + io.undertow + undertow-core + 2.1.0.Final + + + + org.apache.logging.log4j + log4j-core + 2.24.1 + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + commons-io + commons-io + 2.17.0 + + + \ No newline at end of file diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/Dustspeck2Context.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/Dustspeck2Context.java new file mode 100644 index 0000000..b39eeb2 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/Dustspeck2Context.java @@ -0,0 +1,91 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import moe.yo3explorer.dustspeck2.business.nuget.control.*; +import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class Dustspeck2Context +{ + private static Dustspeck2Context _instance; + private static Logger logger; + private String dataDirectory; + + private Dustspeck2Context() + { + logger = LogManager.getLogger(Dustspeck2Context.class); + logger.info("Built context!"); + } + + public static Dustspeck2Context getInstance() + { + if (_instance == null) + { + _instance = new Dustspeck2Context(); + } + return _instance; + } + + public void setDataDirectory(String dataDirectory) + { + if (fileStorage != null) + throw new FileStorageAlreadyWorkingException(); + + this.dataDirectory = dataDirectory; + } + + private FileStorage fileStorage; + public synchronized FileStorage getFileStorage() throws IOException + { + if (this.dataDirectory == null) + throw new DataDirectoryNotConfiguredException(); + + if (fileStorage == null) + { + fileStorage = new FileStorage(dataDirectory); + } + return fileStorage; + } + + private HttpClient httpClient; + public synchronized HttpClient getHttpClient() + { + if (httpClient == null) + httpClient = new HttpClient(); + return httpClient; + } + + private boolean internetConnectionChecked; + private boolean isOffline; + public synchronized boolean isOffline() + { + if (!internetConnectionChecked) + { + isOffline = !InternetConnectionChecker.checkInternetConnection(); + internetConnectionChecked = true; + } + return isOffline; + } + + @NotNull + public byte[] patchJson(byte[] input, String newServer) + { + String sourceJson = IOUtils.toString(input, String.valueOf(StandardCharsets.UTF_8)); + sourceJson = sourceJson.replace("https://api.nuget.org/","http://" + newServer + "/"); + return sourceJson.getBytes(StandardCharsets.UTF_8); + } + + public String guessMimeType(@NotNull String fname) + { + if (fname.endsWith(".nupkg")) + return "application/x-nupkg"; + else if (fname.endsWith(".json")) + return "application/json"; + else + return "octet/stream"; + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java new file mode 100644 index 0000000..7dc16ff --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/IconService.java @@ -0,0 +1,60 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class IconService implements Dustspeck2Service +{ + @Override + public boolean canHandle(String s) + { + return s.startsWith("/v3-flatcontainer/"); + } + + @Override + public void handleRequest(String queryString, String[] vines, HttpServerExchange httpServerExchange) throws IOException + { + String originalUrl = "https://api.nuget.org" + queryString; + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + String mime = dustspeck2.guessMimeType(queryString); + String onDiskFilename = queryString; + + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(onDiskFilename)) + { + byte[] buffer = fileStorage.getFile(queryString); + if (queryString.endsWith(".json")) + { + buffer = dustspeck2.patchJson(buffer, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] file = httpClient.getFile(originalUrl); + fileStorage.writeFile(queryString, file); + if (queryString.endsWith(".json")) + { + file = dustspeck2.patchJson(file, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(file)); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/PackageBaseAddressService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/PackageBaseAddressService.java new file mode 100644 index 0000000..c0f3423 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/PackageBaseAddressService.java @@ -0,0 +1,62 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class PackageBaseAddressService implements Dustspeck2Service +{ + @Override + public boolean canHandle(@NotNull String s) + { + return s.startsWith("/PackageBaseAddress/v3-flatcontainer"); + } + + @Override + public void handleRequest(@NotNull String queryString, String[] vines, HttpServerExchange httpServerExchange) throws IOException + { + String originalUrl = queryString.replace("/PackageBaseAddress",""); + originalUrl = "https://api.nuget.org" + originalUrl;; + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + String mime = dustspeck2.guessMimeType(queryString); + String onDiskFilename = queryString.replace("/PackageBaseAddress",""); + + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(onDiskFilename)) + { + byte[] buffer = fileStorage.getFile(onDiskFilename); + if (queryString.endsWith(".json")) + { + buffer = dustspeck2.patchJson(buffer, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] file = httpClient.getFile(originalUrl); + fileStorage.writeFile(onDiskFilename, file); + if (queryString.endsWith(".json")) + { + file = dustspeck2.patchJson(file, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(file)); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/ReadmeUriTemplateService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/ReadmeUriTemplateService.java new file mode 100644 index 0000000..c5844a7 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/ReadmeUriTemplateService.java @@ -0,0 +1,54 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class ReadmeUriTemplateService implements Dustspeck2Service +{ + @Override + public boolean canHandle(@NotNull String s) + { + return s.startsWith("/ReadmeUriTemplate/v3-flatcontainer/") && s.endsWith("/readme"); + } + + @Override + public void handleRequest(String queryString, @NotNull String[] vines, HttpServerExchange httpServerExchange) throws IOException + { + String readme = vines[vines.length - 1]; + String version = vines[vines.length - 2]; + String packageName = vines[vines.length - 3]; + String liveUrl = String.format("https://api.nuget.org/v3-flatcontainer/%s/%s/%s",packageName,version,readme); + + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(queryString)) + { + byte[] buffer = fileStorage.getFile(queryString); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"text/plain"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] file = httpClient.getFile(liveUrl); + fileStorage.writeFile(queryString, file); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"text/plain"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(file)); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/RegistrationsBaseUrlService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/RegistrationsBaseUrlService.java new file mode 100644 index 0000000..9f9532b --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/RegistrationsBaseUrlService.java @@ -0,0 +1,58 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class RegistrationsBaseUrlService implements Dustspeck2Service +{ + @Override + public boolean canHandle(@NotNull String s) + { + if (!s.endsWith(".json")) + return false; + + return s.startsWith("/RegistrationsBaseUrl/v3/registration5-gz-semver2/"); + } + + @Override + public void handleRequest(String queryString, @NotNull String[] vines, HttpServerExchange httpServerExchange) throws IOException + { + String indexName = vines[vines.length - 1]; + String packageName = vines[vines.length - 2]; + String onDiskFilename = queryString.replace("/RegistrationsBaseUrl",""); + + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(onDiskFilename)) + { + byte[] buffer = fileStorage.getFile(onDiskFilename); + buffer = dustspeck2.patchJson(buffer,httpServerExchange.getHostAndPort()); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] file = httpClient.getFile(String.format("https://api.nuget.org/v3/registration5-gz-semver2/%s/%s", packageName, indexName)); + fileStorage.writeFile(onDiskFilename, file); + file = dustspeck2.patchJson(file,httpServerExchange.getHostAndPort()); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(file)); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/SearchQueryService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/SearchQueryService.java new file mode 100644 index 0000000..a07ea64 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/SearchQueryService.java @@ -0,0 +1,53 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2HttpHandler; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class SearchQueryService implements Dustspeck2Service +{ + @Override + public boolean canHandle(@NotNull String s) + { + return s.equals("/SearchQueryService/query"); + } + + @Override + public void handleRequest(String queryString, String[] vines, @NotNull HttpServerExchange httpServerExchange) throws IOException + { + String filename = queryString + "/" + httpServerExchange.getQueryString(); + + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(filename)) + { + byte[] buffer = fileStorage.getFile(filename); + buffer = dustspeck2.patchJson(buffer,httpServerExchange.getHostAndPort()); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] buffer = httpClient.getFile("https://azuresearch-usnc.nuget.org/query", httpServerExchange.getQueryString()); + fileStorage.writeFile(filename,buffer); + buffer = dustspeck2.patchJson(buffer,httpServerExchange.getHostAndPort()); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VersionPageService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VersionPageService.java new file mode 100644 index 0000000..762a3e7 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VersionPageService.java @@ -0,0 +1,62 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class VersionPageService implements Dustspeck2Service +{ + @Override + public boolean canHandle(@NotNull String s) + { + return s.startsWith("/v3/registration5-gz-semver2/"); + } + + @Override + public void handleRequest(String queryString, String[] vines, HttpServerExchange httpServerExchange) throws IOException + { + String onDiskFilename = String.format("RegistrationsBaseUrl/%s",queryString); + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + String mime = dustspeck2.guessMimeType(queryString); + + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(onDiskFilename)) + { + byte[] buffer = fileStorage.getFile(queryString); + if (queryString.endsWith(".json")) + { + buffer = dustspeck2.patchJson(buffer, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] file = httpClient.getFile(String.format("https://api.nuget.org/%s",queryString)); + fileStorage.writeFile(queryString, file); + if (queryString.endsWith(".json")) + { + file = dustspeck2.patchJson(file, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(file)); + } + + +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityBaseService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityBaseService.java new file mode 100644 index 0000000..002d600 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityBaseService.java @@ -0,0 +1,60 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; + +import java.io.IOException; +import java.nio.ByteBuffer; + +public class VulnerabilityBaseService implements Dustspeck2Service +{ + @Override + public boolean canHandle(String s) + { + return s.startsWith("/v3-vulnerabilities/"); + } + + @Override + public void handleRequest(String queryString, String[] vines, HttpServerExchange httpServerExchange) throws IOException + { + String originalUrl = "https://api.nuget.org" + queryString; + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + String mime = dustspeck2.guessMimeType(queryString); + String onDiskFilename = queryString; + + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(onDiskFilename)) + { + byte[] buffer = fileStorage.getFile(queryString); + if (queryString.endsWith(".json")) + { + buffer = dustspeck2.patchJson(buffer, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] file = httpClient.getFile(originalUrl); + fileStorage.writeFile(queryString, file); + if (queryString.endsWith(".json")) + { + file = dustspeck2.patchJson(file, httpServerExchange.getHostAndPort()); + } + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),mime); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(file)); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityInfoService.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityInfoService.java new file mode 100644 index 0000000..7b922cc --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/boundary/VulnerabilityInfoService.java @@ -0,0 +1,57 @@ +package moe.yo3explorer.dustspeck2.business.nuget.boundary; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.control.FileStorage; +import moe.yo3explorer.dustspeck2.business.nuget.control.HttpClient; +import moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service; +import org.apache.commons.io.IOUtils; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +public class VulnerabilityInfoService implements Dustspeck2Service +{ + @Override + public boolean canHandle(@NotNull String s) + { + return s.equals("/VulnerabilityInfo/v3/vulnerabilities/index.json"); + } + + @Override + public void handleRequest(String queryString, String[] vines, HttpServerExchange httpServerExchange) throws IOException + { + String onDiskFilename = queryString.replace("/VulnerabilityInfo/",""); + + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + FileStorage fileStorage = dustspeck2.getFileStorage(); + if (fileStorage.testForFile(onDiskFilename)) + { + byte[] buffer = fileStorage.getFile(onDiskFilename); + buffer = dustspeck2.patchJson(buffer,httpServerExchange.getHostAndPort()); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(buffer)); + return; + } + + if (dustspeck2.isOffline()) + { + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + return; + } + + HttpClient httpClient = dustspeck2.getHttpClient(); + byte[] file = httpClient.getFile("https://api.nuget.org/v3/vulnerabilities/index.json"); + fileStorage.writeFile(onDiskFilename, file); + file = dustspeck2.patchJson(file,httpServerExchange.getHostAndPort()); + httpServerExchange.setStatusCode(200); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(file)); + } + + +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/DataDirectoryNotConfiguredException.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/DataDirectoryNotConfiguredException.java new file mode 100644 index 0000000..547a528 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/DataDirectoryNotConfiguredException.java @@ -0,0 +1,5 @@ +package moe.yo3explorer.dustspeck2.business.nuget.control; + +public class DataDirectoryNotConfiguredException extends RuntimeException +{ +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/FileStorage.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/FileStorage.java new file mode 100644 index 0000000..328a784 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/FileStorage.java @@ -0,0 +1,58 @@ +package moe.yo3explorer.dustspeck2.business.nuget.control; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class FileStorage +{ + private final Path outdirAsPath; + private final String outdirAsString; + private final File outdirAsFile; + private final Logger logger; + + public FileStorage(String dataDirectory) throws IOException + { + logger = LogManager.getLogger(getClass()); + logger.info("Initialized File Storage"); + + outdirAsString = dataDirectory; + outdirAsPath = Path.of(dataDirectory); + outdirAsFile = outdirAsPath.toFile(); + if (!outdirAsFile.isDirectory()) + { + Files.createDirectories(outdirAsPath); + logger.info(String.format("Created directory: %s", dataDirectory)); + } + } + + public boolean testForFile(String queryString) + { + Path path = Paths.get(outdirAsString,queryString); + File file = path.toFile(); + return file.isFile(); + } + + public byte[] getFile(String queryString) throws IOException + { + Path path = Paths.get(outdirAsString,queryString); + FileInputStream fis = new FileInputStream(path.toFile()); + byte[] result = fis.readAllBytes(); + fis.close(); + return result; + } + + public void writeFile(String queryString, byte[] file) throws IOException + { + Path path = Paths.get(outdirAsString,queryString); + Files.createDirectories(path.getParent()); + Files.write(path,file); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/FileStorageAlreadyWorkingException.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/FileStorageAlreadyWorkingException.java new file mode 100644 index 0000000..62410d3 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/FileStorageAlreadyWorkingException.java @@ -0,0 +1,5 @@ +package moe.yo3explorer.dustspeck2.business.nuget.control; + +public class FileStorageAlreadyWorkingException extends RuntimeException +{ +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/HttpClient.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/HttpClient.java new file mode 100644 index 0000000..0a9570c --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/HttpClient.java @@ -0,0 +1,36 @@ +package moe.yo3explorer.dustspeck2.business.nuget.control; + +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +import java.io.IOException; + +public class HttpClient +{ + private final OkHttpClient client; + + public HttpClient() + { + this.client = new OkHttpClient(); + } + + public byte[] getFile(String path) throws IOException + { + Request request = new Request.Builder() + .url(path) + .build(); + + Call call = client.newCall(request); + Response response = call.execute(); + byte[] bytes = response.body().bytes(); + return bytes; + } + + public byte[] getFile(String path, String queryString) throws IOException + { + String newPath = String.format("%s?%s",path,queryString); + return getFile(newPath); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/InternetConnectionChecker.java b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/InternetConnectionChecker.java new file mode 100644 index 0000000..1c444db --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/business/nuget/control/InternetConnectionChecker.java @@ -0,0 +1,67 @@ +package moe.yo3explorer.dustspeck2.business.nuget.control; + +import okhttp3.Call; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.util.Random; + +public class InternetConnectionChecker +{ + private InternetConnectionChecker() {} + + public static boolean checkInternetConnection() + { + Logger logger = LogManager.getLogger(InternetConnectionChecker.class); + + String[] sites = new String[] + { + "http://www.google.com", "http://www.youtube.com", "http://www.amazon.com", + "http://www.archive.org", "http://store.steampowered.com", "http://www.microsoft.com", + "http://www.apple.com", "http://www.facebook.com", "http://www.nintendo.co.jp", + "http://www.sony.co.jp", "http://www.discord.com", "http://www.netflix.com", + "http://www.spotify.com", "http://www.vw.de", "http://www.nestle.com", "http://www.disney.com", + "http://www.toyota.co.jp", "http://www.bp.com", "http://www.shell.com", "http://www.basf.de", + "http://www.siemens.de", "http://www.boeing.com", "http://www.ibm.com", "http://www.axa.fr", + "http://www.bahn.de", "http://www.intel.com", "http://www.samsung.com", "http://www.tesla.com", + "http://de.wikipedia.org", "http://www.debian.org", "http://www.sega.co.jp", + "http://www.nuget.org/", "http://www.github.com", "http://www.msftconnecttest.com/ncsi.txt" + }; + + int fails = 0; + OkHttpClient client = new OkHttpClient(); + Random rng = new Random(); + while (true) + { + String site = sites[rng.nextInt(sites.length)]; + + Request request = new Request.Builder() + .url(site) + .build(); + + try + { + Call call = client.newCall(request); + Response execute = call.execute(); + int code = execute.code(); + logger.info(String.format("GET %s returned %d, so I'm gonna assume I have internet.",site,code)); + execute.close(); + return true; + } + catch (Throwable t) + { + fails++; + } + if (fails >= 3) + { + logger.info("Could not verify the internet connection, so I'm gonna assume I'm offline."); + return false; + } + } + + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/presentation/Dustspeck2HttpHandler.java b/src/main/java/moe/yo3explorer/dustspeck2/presentation/Dustspeck2HttpHandler.java new file mode 100644 index 0000000..a3f20a4 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/presentation/Dustspeck2HttpHandler.java @@ -0,0 +1,55 @@ +package moe.yo3explorer.dustspeck2.presentation; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import moe.yo3explorer.dustspeck2.business.nuget.boundary.Dustspeck2Context; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.ServiceLoader; + +public class Dustspeck2HttpHandler implements HttpHandler +{ + private static Logger logger; + private final List services; + + public Dustspeck2HttpHandler() + { + if (logger == null) + { + logger = LogManager.getLogger(getClass()); + logger.info("Loaded the HTTP handler."); + } + + ServiceLoader loader = ServiceLoader.load(Dustspeck2Service.class); + services = loader.stream().map(ServiceLoader.Provider::get).toList(); + logger.info(String.format("Discovered %d services",services.size())); + } + + @Override + public void handleRequest(@NotNull HttpServerExchange httpServerExchange) throws Exception + { + String queryString = httpServerExchange.getRequestURI(); + logger.info(String.format("%s %s", httpServerExchange.getRequestMethod().toString(), queryString)); + + String[] vines = queryString.split("/"); + + httpServerExchange.getResponseHeaders().put(new HttpString("Server"),"sophia.net/Dustspeck2"); + + for (Dustspeck2Service serviceCandidate: services) + { + if (serviceCandidate.canHandle(queryString)) + { + serviceCandidate.handleRequest(queryString, vines, httpServerExchange); + return; + } + } + + httpServerExchange.setStatusCode(404); + httpServerExchange.getResponseSender().send(""); + httpServerExchange.getResponseSender().close(); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/presentation/Dustspeck2Service.java b/src/main/java/moe/yo3explorer/dustspeck2/presentation/Dustspeck2Service.java new file mode 100644 index 0000000..8d6df5d --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/presentation/Dustspeck2Service.java @@ -0,0 +1,13 @@ +package moe.yo3explorer.dustspeck2.presentation; + +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; + +import java.io.IOException; + +public interface Dustspeck2Service +{ + boolean canHandle(String s); + + void handleRequest(String queryString, String[] vines, HttpServerExchange httpServerExchange) throws IOException; +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/presentation/EnvironmentVariableMissingException.java b/src/main/java/moe/yo3explorer/dustspeck2/presentation/EnvironmentVariableMissingException.java new file mode 100644 index 0000000..df37020 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/presentation/EnvironmentVariableMissingException.java @@ -0,0 +1,9 @@ +package moe.yo3explorer.dustspeck2.presentation; + +public class EnvironmentVariableMissingException extends RuntimeException +{ + public EnvironmentVariableMissingException(String setting) + { + super(String.format("Environment vatiable %s is not configured.", setting)); + } +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/presentation/Main.java b/src/main/java/moe/yo3explorer/dustspeck2/presentation/Main.java new file mode 100644 index 0000000..1923e47 --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/presentation/Main.java @@ -0,0 +1,40 @@ +package moe.yo3explorer.dustspeck2.presentation; + +import io.undertow.Undertow; +import io.undertow.server.HttpHandler; +import moe.yo3explorer.dustspeck2.business.nuget.boundary.Dustspeck2Context; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.Map; + +public class Main +{ + public static void main(String[] args) + { + Logger logger = LogManager.getLogger(Main.class); + logger.info("Hello! This is Dustspeck2!"); + + Map getenv = System.getenv(); + String[] env = new String[] {"DATA_DIRECTORY"}; + for (String setting : env) + { + if (!getenv.containsKey(setting)) + { + throw new EnvironmentVariableMissingException(setting); + } + } + + Dustspeck2Context dustspeck2 = Dustspeck2Context.getInstance(); + dustspeck2.setDataDirectory(getenv.get("DATA_DIRECTORY")); + + Dustspeck2HttpHandler dustspeck2HttpHandler = new Dustspeck2HttpHandler(); + + Undertow server = Undertow.builder() + .addHttpListener(8080, "0.0.0.0") + .setHandler(dustspeck2HttpHandler).build(); + + logger.info("Began listening on port 8080..."); + server.start(); + } +} \ No newline at end of file diff --git a/src/main/java/moe/yo3explorer/dustspeck2/presentation/ResourceService.java b/src/main/java/moe/yo3explorer/dustspeck2/presentation/ResourceService.java new file mode 100644 index 0000000..b288e0e --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/presentation/ResourceService.java @@ -0,0 +1,63 @@ +package moe.yo3explorer.dustspeck2.presentation; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.apache.commons.io.IOUtils; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +public class ResourceService implements Dustspeck2Service +{ + @Override + public boolean canHandle(@NotNull String s) + { + switch (s) + { + case "/index.json": + case "/favicon.ico": + return true; + default: + return false; + } + } + + private String indexJson; + private byte[] faviconIco; + + @Override + public void handleRequest(@NotNull String queryString, String[] vines, @NotNull HttpServerExchange httpServerExchange) throws IOException + { + String hostAndPort = httpServerExchange.getHostAndPort(); + hostAndPort = String.format("http://%s",hostAndPort); + + switch (queryString) + { + case "/index.json": + if (indexJson == null) + { + InputStream indexStream = getClass().getClassLoader().getResourceAsStream("index.json"); + indexJson = IOUtils.toString(indexStream, StandardCharsets.UTF_8); + indexJson = indexJson.replace("{0}", hostAndPort); + } + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(indexJson); + httpServerExchange.getResponseSender().close(); + return; + case "/favicon.ico": + if (faviconIco == null) + { + InputStream faviconStream = getClass().getClassLoader().getResourceAsStream("favicon.ico"); + faviconIco = IOUtils.toByteArray(faviconStream); + } + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Content-Type"),"application/json"); + httpServerExchange.getResponseSender().send(ByteBuffer.wrap(faviconIco)); + httpServerExchange.getResponseSender().close(); + return; + } + } + +} diff --git a/src/main/java/moe/yo3explorer/dustspeck2/presentation/RootRedirectService.java b/src/main/java/moe/yo3explorer/dustspeck2/presentation/RootRedirectService.java new file mode 100644 index 0000000..b2549cd --- /dev/null +++ b/src/main/java/moe/yo3explorer/dustspeck2/presentation/RootRedirectService.java @@ -0,0 +1,25 @@ +package moe.yo3explorer.dustspeck2.presentation; + +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; + +public class RootRedirectService implements Dustspeck2Service +{ + @Override + public boolean canHandle(String s) + { + return s.equals("/"); + } + + @Override + public void handleRequest(String queryString, String[] vines, @NotNull HttpServerExchange httpServerExchange) throws IOException + { + httpServerExchange.setStatusCode(301); + httpServerExchange.getResponseHeaders().put(HttpString.tryFromString("Location"),"/index.json"); + httpServerExchange.getResponseSender().send(""); + httpServerExchange.getResponseSender().close(); + } +} diff --git a/src/main/resources/META-INF/services/moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service b/src/main/resources/META-INF/services/moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service new file mode 100644 index 0000000..1f853f6 --- /dev/null +++ b/src/main/resources/META-INF/services/moe.yo3explorer.dustspeck2.presentation.Dustspeck2Service @@ -0,0 +1,10 @@ +moe.yo3explorer.dustspeck2.presentation.RootRedirectService +moe.yo3explorer.dustspeck2.presentation.ResourceService +moe.yo3explorer.dustspeck2.business.nuget.boundary.RegistrationsBaseUrlService +moe.yo3explorer.dustspeck2.business.nuget.boundary.ReadmeUriTemplateService +moe.yo3explorer.dustspeck2.business.nuget.boundary.VulnerabilityInfoService +moe.yo3explorer.dustspeck2.business.nuget.boundary.SearchQueryService +moe.yo3explorer.dustspeck2.business.nuget.boundary.VersionPageService +moe.yo3explorer.dustspeck2.business.nuget.boundary.PackageBaseAddressService +moe.yo3explorer.dustspeck2.business.nuget.boundary.VulnerabilityBaseService +moe.yo3explorer.dustspeck2.business.nuget.boundary.IconService \ No newline at end of file diff --git a/src/main/resources/favicon.ico b/src/main/resources/favicon.ico new file mode 100644 index 0000000..fb0980c Binary files /dev/null and b/src/main/resources/favicon.ico differ diff --git a/src/main/resources/index.json b/src/main/resources/index.json new file mode 100644 index 0000000..ec0a12a --- /dev/null +++ b/src/main/resources/index.json @@ -0,0 +1,182 @@ +{ + "version": "3.0.0", + "resources": [ + { + "@id": "{0}/SearchQueryService/query", + "@type": "SearchQueryService", + "comment": "Query endpoint of NuGet Search service (primary)" + }, + { + "@id": "{0}/SearchAutocompleteService/autocomplete", + "@type": "SearchAutocompleteService", + "comment": "Autocomplete endpoint of NuGet Search service (primary)" + }, + { + "@id": "{0}/SearchGalleryQueryService/", + "@type": "SearchGalleryQueryService/3.0.0-rc", + "comment": "Azure Website based Search Service used by Gallery (primary)" + }, + { + "@id": "{0}/RegistrationsBaseUrl/v3/registration5-semver1/", + "@type": "RegistrationsBaseUrl", + "comment": "Base URL of Azure storage where NuGet package registration info is stored" + }, + { + "@id": "{0}/PackageBaseAddress/v3-flatcontainer/", + "@type": "PackageBaseAddress/3.0.0", + "comment": "Base URL of where NuGet packages are stored, in the format {0}/api.nuget.org/v3-flatcontainer/{id-lower}/{version-lower}/{id-lower}.{version-lower}.nupkg" + }, + { + "@id": "{0}/LegacyGallery/api/v2", + "@type": "LegacyGallery" + }, + { + "@id": "{0}/LegacyGallery/api/v2", + "@type": "LegacyGallery/2.0.0" + }, + { + "@id": "{0}/PackagePublish/api/v2/package", + "@type": "PackagePublish/2.0.0" + }, + { + "@id": "{0}/SymbolPackagePublish/api/v2/symbolpackage", + "@type": "SymbolPackagePublish/4.9.0", + "comment": "The gallery symbol publish endpoint." + }, + { + "@id": "{0}/SearchQueryService/query", + "@type": "SearchQueryService/3.0.0-rc", + "comment": "Query endpoint of NuGet Search service (primary) used by RC clients" + }, + { + "@id": "{0}/SearchQueryService/query", + "@type": "SearchQueryService/3.0.0-rc", + "comment": "Query endpoint of NuGet Search service (secondary) used by RC clients" + }, + { + "@id": "{0}/SearchQueryService/query", + "@type": "SearchQueryService/3.5.0", + "comment": "Query endpoint of NuGet Search service (primary) that supports package type filtering" + }, + { + "@id": "{0}/SearchQueryService/query", + "@type": "SearchQueryService/3.5.0", + "comment": "Query endpoint of NuGet Search service (secondary) that supports package type filtering" + }, + { + "@id": "{0}/SearchAutocompleteService/autocomplete", + "@type": "SearchAutocompleteService/3.0.0-rc", + "comment": "Autocomplete endpoint of NuGet Search service (primary) used by RC clients" + }, + { + "@id": "{0}/SearchAutocompleteService/autocomplete", + "@type": "SearchAutocompleteService/3.0.0-rc", + "comment": "Autocomplete endpoint of NuGet Search service (secondary) used by RC clients" + }, + { + "@id": "{0}/SearchAutocompleteService/autocomplete", + "@type": "SearchAutocompleteService/3.5.0", + "comment": "Autocomplete endpoint of NuGet Search service (primary) that supports package type filtering" + }, + { + "@id": "{0}/SearchAutocompleteService/autocomplete", + "@type": "SearchAutocompleteService/3.5.0", + "comment": "Autocomplete endpoint of NuGet Search service (secondary) that supports package type filtering" + }, + { + "@id": "{0}/RegistrationsBaseUrl/v3/registration5-semver1/", + "@type": "RegistrationsBaseUrl/3.0.0-rc", + "comment": "Base URL of Azure storage where NuGet package registration info is stored used by RC clients. This base URL does not include SemVer 2.0.0 packages." + }, + { + "@id": "{0}/ReportAbuseUriTemplate/packages/{id}/{version}/ReportAbuse", + "@type": "ReportAbuseUriTemplate/3.0.0-rc", + "comment": "URI template used by NuGet Client to construct Report Abuse URL for packages used by RC clients" + }, + { + "@id": "{0}/PackageDisplayMetadataUriTemplate/v3/registration5-semver1/{id-lower}/index.json", + "@type": "PackageDisplayMetadataUriTemplate/3.0.0-rc", + "comment": "URI template used by NuGet Client to construct display metadata for Packages using ID" + }, + { + "@id": "{0}/PackageVersionDisplayMetadataUriTemplate/v3/registration5-semver1/{id-lower}/{version-lower}.json", + "@type": "PackageVersionDisplayMetadataUriTemplate/3.0.0-rc", + "comment": "URI template used by NuGet Client to construct display metadata for Packages using ID, Version" + }, + { + "@id": "{0}/SearchQueryService/query", + "@type": "SearchQueryService/3.0.0-beta", + "comment": "Query endpoint of NuGet Search service (primary) used by beta clients" + }, + { + "@id": "{0}/SearchQueryService/query", + "@type": "SearchQueryService/3.0.0-beta", + "comment": "Query endpoint of NuGet Search service (secondary) used by beta clients" + }, + { + "@id": "{0}/SearchAutocompleteService/autocomplete", + "@type": "SearchAutocompleteService/3.0.0-beta", + "comment": "Autocomplete endpoint of NuGet Search service (primary) used by beta clients" + }, + { + "@id": "{0}/SearchAutocompleteService/autocomplete", + "@type": "SearchAutocompleteService/3.0.0-beta", + "comment": "Autocomplete endpoint of NuGet Search service (secondary) used by beta clients" + }, + { + "@id": "{0}/RegistrationsBaseUrl/v3/registration5-semver1/", + "@type": "RegistrationsBaseUrl/3.0.0-beta", + "comment": "Base URL of Azure storage where NuGet package registration info is stored used by Beta clients. This base URL does not include SemVer 2.0.0 packages." + }, + { + "@id": "{0}/ReportAbuseUriTemplate/packages/{id}/{version}/ReportAbuse", + "@type": "ReportAbuseUriTemplate/3.0.0-beta", + "comment": "URI template used by NuGet Client to construct Report Abuse URL for packages" + }, + { + "@id": "{0}/PackageDetailsUriTemplate/packages/{id}/{version}?_src=template", + "@type": "PackageDetailsUriTemplate/5.1.0", + "comment": "URI template used by NuGet Client to construct details URL for packages" + }, + { + "@id": "{0}/OwnerDetailsUriTemplate/profiles/{owner}?_src=template", + "@type": "OwnerDetailsUriTemplate/6.11.0", + "comment": "URI template used by NuGet Client to construct owner URL for packages" + }, + { + "@id": "{0}/RegistrationsBaseUrl/v3/registration5-gz-semver1/", + "@type": "RegistrationsBaseUrl/3.4.0", + "comment": "Base URL of Azure storage where NuGet package registration info is stored in GZIP format. This base URL does not include SemVer 2.0.0 packages." + }, + { + "@id": "{0}/RegistrationsBaseUrl/v3/registration5-gz-semver2/", + "@type": "RegistrationsBaseUrl/3.6.0", + "comment": "Base URL of Azure storage where NuGet package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages." + }, + { + "@id": "{0}/RegistrationsBaseUrl/v3/registration5-gz-semver2/", + "@type": "RegistrationsBaseUrl/Versioned", + "clientVersion": "4.3.0-alpha", + "comment": "Base URL of Azure storage where NuGet package registration info is stored in GZIP format. This base URL includes SemVer 2.0.0 packages." + }, + { + "@id": "{0}/VulnerabilityInfo/v3/vulnerabilities/index.json", + "@type": "VulnerabilityInfo/6.7.0", + "comment": "The endpoint for discovering information about vulnerabilities of packages in this package source." + }, + { + "@id": "{0}/Catalog/v3/catalog0/index.json", + "@type": "Catalog/3.0.0", + "comment": "Index of the NuGet package catalog." + }, + { + "@id": "{0}/ReadmeUriTemplate/v3-flatcontainer/{lower_id}/{lower_version}/readme", + "@type": "ReadmeUriTemplate/6.13.0", + "comment": "URI template used by NuGet Client to construct a URL for downloading a package's README." + } + ], + "@context": { + "@vocab": "http://schema.nuget.org/services#", + "comment": "http://www.w3.org/2000/01/rdf-schema#comment" + } +} \ No newline at end of file diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..d053883 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file