Files
Nextus-Web/src/main/java/dev/coph/nextusweb/server/tls/TlsConfig.java
T
CodingPhoenix 893bb0b7bd
CI - Test, Publish and Release / run-tests (push) Failing after 15s
CI - Test, Publish and Release / create-release (push) Has been skipped
CI - Test, Publish and Release / check-and-publish (push) Has been skipped
Reformat code comments for consistency and clarity across all classes
2026-06-15 07:27:07 +02:00

125 lines
4.9 KiB
Java

package dev.coph.nextusweb.server.tls;
import io.netty.buffer.ByteBufAllocator;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import javax.net.ssl.SSLException;
import java.io.File;
import java.io.InputStream;
import java.util.Objects;
/**
* Configuration that enables TLS (HTTPS / WSS) on the server. Holds a ready-built Netty
* {@link SslContext} and produces the per-connection {@link SslHandler} the pipeline installs as
* its first handler.
*
* <p>Enabling TLS is meant to be a one-liner — point the factory at a PEM certificate chain and
* private key and pass the result to {@code HttpServer.withTls(...)}:</p>
* <pre>{@code
* HttpServer.builder(443, router)
* .withTls(TlsConfig.fromPem(new File("fullchain.pem"), new File("privkey.pem")))
* .start();
* }</pre>
*
* <p>For full control (custom cipher suites, client-auth / mutual TLS, a non-default provider)
* build a Netty {@link SslContext} yourself and wrap it with {@link #fromSslContext(SslContext)}.
* The {@code SslContext} is built once and reused for every connection, so it is cheap per
* request.</p>
*/
public final class TlsConfig {
/**
* The pre-built, shareable server SSL context.
*/
private final SslContext sslContext;
private TlsConfig(SslContext sslContext) {
this.sslContext = Objects.requireNonNull(sslContext, "sslContext");
}
/**
* Builds a TLS configuration from a PEM-encoded certificate chain and an unencrypted
* PKCS#8 private key.
*
* @param certificateChain the PEM file containing the certificate (chain)
* @param privateKey the PEM file containing the PKCS#8 private key
* @return a TLS configuration
* @throws IllegalStateException if the certificate/key cannot be loaded
*/
public static TlsConfig fromPem(File certificateChain, File privateKey) {
return fromPem(certificateChain, privateKey, null);
}
/**
* Builds a TLS configuration from a PEM-encoded certificate chain and a (optionally
* password-protected) PKCS#8 private key.
*
* @param certificateChain the PEM file containing the certificate (chain)
* @param privateKey the PEM file containing the PKCS#8 private key
* @param keyPassword the password protecting {@code privateKey}, or {@code null} if none
* @return a TLS configuration
* @throws IllegalStateException if the certificate/key cannot be loaded
*/
public static TlsConfig fromPem(File certificateChain, File privateKey, String keyPassword) {
Objects.requireNonNull(certificateChain, "certificateChain");
Objects.requireNonNull(privateKey, "privateKey");
try {
return new TlsConfig(SslContextBuilder.forServer(certificateChain, privateKey, keyPassword).build());
} catch (SSLException | RuntimeException e) {
throw new IllegalStateException("Failed to initialise TLS from PEM files", e);
}
}
/**
* Builds a TLS configuration from PEM-encoded streams, for certificates/keys loaded from the
* classpath or another non-file source. The caller retains ownership of the streams.
*
* @param certificateChain a stream of the PEM certificate (chain)
* @param privateKey a stream of the PEM PKCS#8 private key
* @param keyPassword the password protecting {@code privateKey}, or {@code null} if none
* @return a TLS configuration
* @throws IllegalStateException if the certificate/key cannot be loaded
*/
public static TlsConfig fromPem(InputStream certificateChain, InputStream privateKey, String keyPassword) {
Objects.requireNonNull(certificateChain, "certificateChain");
Objects.requireNonNull(privateKey, "privateKey");
try {
return new TlsConfig(SslContextBuilder.forServer(certificateChain, privateKey, keyPassword).build());
} catch (SSLException | RuntimeException e) {
throw new IllegalStateException("Failed to initialise TLS from PEM streams", e);
}
}
/**
* Wraps a fully configured Netty {@link SslContext}, for advanced setups such as custom cipher
* suites or mutual TLS.
*
* @param sslContext a server-mode SSL context
* @return a TLS configuration backed by the given context
*/
public static TlsConfig fromSslContext(SslContext sslContext) {
return new TlsConfig(sslContext);
}
/**
* Creates a new per-connection {@link SslHandler} from the shared context.
*
* @param alloc the channel's buffer allocator
* @return a fresh TLS handler for one connection
*/
public SslHandler newHandler(ByteBufAllocator alloc) {
return sslContext.newHandler(alloc);
}
/**
* Returns the underlying Netty SSL context.
*
* @return the shared server SSL context
*/
public SslContext sslContext() {
return sslContext;
}
}