|
|
|
@ -2,15 +2,31 @@ package org.qortal.api;
|
|
|
|
|
|
|
|
|
|
import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource; |
|
|
|
|
|
|
|
|
|
import java.io.InputStream; |
|
|
|
|
import java.net.InetAddress; |
|
|
|
|
import java.net.InetSocketAddress; |
|
|
|
|
import java.nio.file.Files; |
|
|
|
|
import java.nio.file.Path; |
|
|
|
|
import java.nio.file.Paths; |
|
|
|
|
import java.security.KeyStore; |
|
|
|
|
import java.security.SecureRandom; |
|
|
|
|
|
|
|
|
|
import javax.net.ssl.KeyManagerFactory; |
|
|
|
|
import javax.net.ssl.SSLContext; |
|
|
|
|
|
|
|
|
|
import org.eclipse.jetty.http.HttpVersion; |
|
|
|
|
import org.eclipse.jetty.rewrite.handler.RedirectPatternRule; |
|
|
|
|
import org.eclipse.jetty.rewrite.handler.RewriteHandler; |
|
|
|
|
import org.eclipse.jetty.server.CustomRequestLog; |
|
|
|
|
import org.eclipse.jetty.server.HttpConfiguration; |
|
|
|
|
import org.eclipse.jetty.server.HttpConnectionFactory; |
|
|
|
|
import org.eclipse.jetty.server.OptionalSslConnectionFactory; |
|
|
|
|
import org.eclipse.jetty.server.RequestLog; |
|
|
|
|
import org.eclipse.jetty.server.RequestLogWriter; |
|
|
|
|
import org.eclipse.jetty.server.SecureRequestCustomizer; |
|
|
|
|
import org.eclipse.jetty.server.Server; |
|
|
|
|
import org.eclipse.jetty.server.ServerConnector; |
|
|
|
|
import org.eclipse.jetty.server.SslConnectionFactory; |
|
|
|
|
import org.eclipse.jetty.server.handler.ErrorHandler; |
|
|
|
|
import org.eclipse.jetty.server.handler.InetAccessHandler; |
|
|
|
|
import org.eclipse.jetty.servlet.DefaultServlet; |
|
|
|
@ -18,6 +34,7 @@ import org.eclipse.jetty.servlet.FilterHolder;
|
|
|
|
|
import org.eclipse.jetty.servlet.ServletContextHandler; |
|
|
|
|
import org.eclipse.jetty.servlet.ServletHolder; |
|
|
|
|
import org.eclipse.jetty.servlets.CrossOriginFilter; |
|
|
|
|
import org.eclipse.jetty.util.ssl.SslContextFactory; |
|
|
|
|
import org.glassfish.jersey.server.ResourceConfig; |
|
|
|
|
import org.glassfish.jersey.servlet.ServletContainer; |
|
|
|
|
import org.qortal.api.resource.AnnotationPostProcessor; |
|
|
|
@ -56,9 +73,58 @@ public class ApiService {
|
|
|
|
|
public void start() { |
|
|
|
|
try { |
|
|
|
|
// Create API server
|
|
|
|
|
InetAddress bindAddr = InetAddress.getByName(Settings.getInstance().getBindAddress()); |
|
|
|
|
InetSocketAddress endpoint = new InetSocketAddress(bindAddr, Settings.getInstance().getApiPort()); |
|
|
|
|
this.server = new Server(endpoint); |
|
|
|
|
|
|
|
|
|
// SSL support if requested
|
|
|
|
|
String keystorePathname = Settings.getInstance().getSslKeystorePathname(); |
|
|
|
|
String keystorePassword = Settings.getInstance().getSslKeystorePassword(); |
|
|
|
|
|
|
|
|
|
if (keystorePathname != null && keystorePassword != null) { |
|
|
|
|
// SSL version
|
|
|
|
|
if (!Files.isReadable(Path.of(keystorePathname))) |
|
|
|
|
throw new RuntimeException("Failed to start SSL API due to broken keystore"); |
|
|
|
|
|
|
|
|
|
// BouncyCastle-specific SSLContext build
|
|
|
|
|
SSLContext sslContext = SSLContext.getInstance("TLS", "BCJSSE"); |
|
|
|
|
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX", "BCJSSE"); |
|
|
|
|
|
|
|
|
|
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType(), "BC"); |
|
|
|
|
|
|
|
|
|
try (InputStream keystoreStream = Files.newInputStream(Paths.get(keystorePathname))) { |
|
|
|
|
keyStore.load(keystoreStream, keystorePassword.toCharArray()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
keyManagerFactory.init(keyStore, keystorePassword.toCharArray()); |
|
|
|
|
sslContext.init(keyManagerFactory.getKeyManagers(), null, new SecureRandom()); |
|
|
|
|
|
|
|
|
|
SslContextFactory.Server sslContextFactory = new SslContextFactory.Server(); |
|
|
|
|
sslContextFactory.setSslContext(sslContext); |
|
|
|
|
|
|
|
|
|
this.server = new Server(); |
|
|
|
|
|
|
|
|
|
HttpConfiguration httpConfig = new HttpConfiguration(); |
|
|
|
|
httpConfig.setSecureScheme("https"); |
|
|
|
|
httpConfig.setSecurePort(Settings.getInstance().getApiPort()); |
|
|
|
|
|
|
|
|
|
SecureRequestCustomizer src = new SecureRequestCustomizer(); |
|
|
|
|
httpConfig.addCustomizer(src); |
|
|
|
|
|
|
|
|
|
HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(httpConfig); |
|
|
|
|
SslConnectionFactory sslConnectionFactory = new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()); |
|
|
|
|
|
|
|
|
|
ServerConnector portUnifiedConnector = new ServerConnector(this.server, |
|
|
|
|
new OptionalSslConnectionFactory(sslConnectionFactory, HttpVersion.HTTP_1_1.asString()), |
|
|
|
|
sslConnectionFactory, |
|
|
|
|
httpConnectionFactory); |
|
|
|
|
portUnifiedConnector.setHost(Settings.getInstance().getBindAddress()); |
|
|
|
|
portUnifiedConnector.setPort(Settings.getInstance().getApiPort()); |
|
|
|
|
|
|
|
|
|
this.server.addConnector(portUnifiedConnector); |
|
|
|
|
} else { |
|
|
|
|
// Non-SSL
|
|
|
|
|
InetAddress bindAddr = InetAddress.getByName(Settings.getInstance().getBindAddress()); |
|
|
|
|
InetSocketAddress endpoint = new InetSocketAddress(bindAddr, Settings.getInstance().getApiPort()); |
|
|
|
|
this.server = new Server(endpoint); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Error handler
|
|
|
|
|
ErrorHandler errorHandler = new ApiErrorHandler(); |
|
|
|
|