All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.ipokerface.aps.PushClientBuilder Maven / Gradle / Ivy

The newest version!
package cn.ipokerface.aps;

import cn.ipokerface.aps.auth.ApnsSignKey;
import cn.ipokerface.aps.utils.P12Util;
import io.netty.handler.codec.http2.Http2FrameLogger;
import io.netty.handler.codec.http2.Http2SecurityUtil;
import io.netty.handler.ssl.*;
import io.netty.util.ReferenceCounted;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.time.Duration;

/**
 * Created by       PokerFace
 * Create Date      2020-08-24.
 * Email:           [email protected]
 * Version          1.0.0
 * 

* Description: */ public class PushClientBuilder { private static final Logger logger = LoggerFactory.getLogger(PushClientBuilder.class); /** * {@link cn.ipokerface.aps.PushClient.Environment} * */ private PushClient.Environment environment; // default topic private String topic; /** * Sets the TLS credentials for the client under construction. Clients constructed with TLS credentials will use * LS-based authentication when sending push notifications. */ private X509Certificate certificate; private PrivateKey certificatePrivateKey; private String certificatePrivateKeyPassword; private ApnsSignKey signKey; private Duration tokenExpiration = Duration.ofMinutes(50); private File trustedServerCertificatePemFile; private InputStream trustedServerCertificateInputStream; private X509Certificate[] trustedServerCertificates; // client build listener private PushClientMetricsListener metricsListener; private Duration connectionTimeout; // idle time interval... private Duration idleInterval = Duration.ofMinutes(1); private Http2FrameLogger frameLogger; private int poolCapacity = 1; public PushClientBuilder() { } /** * * {@link cn.ipokerface.aps.PushClient.Environment#Production} * {@link cn.ipokerface.aps.PushClient.Environment#Sandbox} * * @see Sending Notification Requests to APNs * * @since 1.0.0 * * @param env * @return */ public PushClientBuilder environment(PushClient.Environment env) { this.environment = env; return this; } /** * set default topic of this push client... * * @param topic * @return */ public PushClientBuilder topic(String topic) { this.topic = topic; return this; } /** *

Sets the TLS credentials for the client under construction using the contents of the given PKCS#12 file. * Clients constructed with TLS credentials will use TLS-based authentication when sending push notifications. The * PKCS#12 file must contain a certificate/private key pair.

* *

Clients may not have both TLS credentials and a signing key.

* * @param p12FilePath a PKCS#12-formatted file containing the certificate and private key to be used to identify the * client to the APNs server * @param password the password to be used to decrypt the contents of the given PKCS#12 file; passwords may be * blank (i.e. {@code ""}), but must not be {@code null} * * @throws SSLException if the given PKCS#12 file could not be loaded or if any other SSL-related problem arises * when constructing the context * @throws IOException if any IO problem occurred while attempting to read the given PKCS#12 file, or the PKCS#12 * file could not be found * * @return a reference to this builder * */ public PushClientBuilder credential(String p12FilePath, String password) throws SSLException, IOException { return this.credential(new FileInputStream(p12FilePath), password); } /** *

Sets the TLS credentials for the client under construction using the data from the given PKCS#12 input stream. * Clients constructed with TLS credentials will use TLS-based authentication when sending push notifications. The * PKCS#12 data must contain a certificate/private key pair.

* *

Clients may not have both TLS credentials and a signing key.

* * @param p12FileInputStream an input stream to a PKCS#12-formatted file containing the certificate and private key to * be used to identify the client to the APNs server * @param password the password to be used to decrypt the contents of the given PKCS#12 file; passwords may be * blank (i.e. {@code ""}), but must not be {@code null} * * @throws SSLException if the given PKCS#12 file could not be loaded or if any other SSL-related problem arises * when constructing the context * @throws IOException if any IO problem occurred while attempting to read the given PKCS#12 input stream * * @return a reference to this builder * */ public PushClientBuilder credential(InputStream p12FileInputStream, String password) throws SSLException, IOException { final X509Certificate x509Certificate; final PrivateKey privateKey; try { final KeyStore.PrivateKeyEntry privateKeyEntry = P12Util.getFirstPrivateKeyEntryFromP12InputStream(p12FileInputStream, password); final Certificate certificate = privateKeyEntry.getCertificate(); if (!(certificate instanceof X509Certificate)) { throw new KeyStoreException("Found a certificate in the provided PKCS#12 file, but it was not an X.509 certificate."); } x509Certificate = (X509Certificate) certificate; privateKey = privateKeyEntry.getPrivateKey(); } catch (final KeyStoreException e) { throw new SSLException(e); } return this.clientCredentials(x509Certificate, privateKey, password); } /** *

Sets the TLS credentials for the client under construction. Clients constructed with TLS credentials will use * TLS-based authentication when sending push notifications.

* *

Clients may not have both TLS credentials and a signing key.

* * @param certificate the certificate to be used to identify the client to the APNs server * @param privateKey the private key for the client certificate * @param privateKeyPassword the password to be used to decrypt the private key; may be {@code null} if the private * key does not require a password * * @return a reference to this builder * * @since 0.8 */ public PushClientBuilder clientCredentials(final X509Certificate certificate, final PrivateKey privateKey, final String privateKeyPassword) { this.certificate = certificate; this.certificatePrivateKey = privateKey; this.certificatePrivateKeyPassword = privateKeyPassword; return this; } /** *

Sets the signing key for the client under construction. Clients constructed with a signing key will use * token-based authentication when sending push notifications.

* *

Clients may not have both a signing key and TLS credentials.

* * @param signKey the signing key to be used by the client under construction * * @return a reference to this builder * * @see ApnsSignKey#loadFromPkcs8File(File, String, String) * @see ApnsSignKey#loadFromInputStream(InputStream, String, String) * */ public PushClientBuilder signingKey(final ApnsSignKey signKey) { this.signKey = signKey; return this; } /** *

Sets the duration after which authentication tokens should expire and be regenerated from the signing key for * clients using token-based authentication. Has no effect for clients using TLS-based authentication.

* *

At the time of writing, the APNs server will treat tokens as "expired" after 60 minutes. The default * expiration duration for clients using token-based authentication is 50 minutes. Callers should not set a * non-default value unless the upstream behavior changes.

* * @param tokenExpiration the duration after which authentication tokens should expire * * @return a reference to this builder * * @since 0.13.11 */ public PushClientBuilder tokenExpiration(final Duration tokenExpiration) { this.tokenExpiration = tokenExpiration; return this; } /** *

Sets the trusted certificate chain for the client under construction using the contents of the given PEM * file. If not set (or {@code null}), the client will use the JVM's default trust manager.

* *

Callers will generally not need to set a trusted server certificate chain in normal operation, but may wish * to do so for certificate pinning * or connecting to a mock server for integration testing or benchmarking.

* * @param certificatePemFile a PEM file containing one or more trusted certificates * * @return a reference to this builder * * @since 0.8 */ public PushClientBuilder trustedServerCertificateChain(final File certificatePemFile) { this.trustedServerCertificatePemFile = certificatePemFile; return this; } /** *

Sets the trusted certificate chain for the client under construction using the contents of the given PEM * input stream. If not set (or {@code null}), the client will use the JVM's default trust manager.

* *

Callers will generally not need to set a trusted server certificate chain in normal operation, but may wish * to do so for certificate pinning * or connecting to a mock server for integration testing or benchmarking.

* * @param certificateInputStream an input stream to PEM-formatted data containing one or more trusted certificates * * @return a reference to this builder * * @since 0.8 */ public PushClientBuilder trustedServerCertificateChain(final InputStream certificateInputStream) { this.trustedServerCertificateInputStream = certificateInputStream; return this; } /** *

Sets the trusted certificate chain for the client under construction. If not set (or {@code null}), the * client will use the JVM's default trust manager.

* *

Callers will generally not need to set a trusted server certificate chain in normal operation, but may wish * to do so for certificate pinning * or connecting to a mock server for integration testing or benchmarking.

* * @param certificates one or more trusted certificates * * @return a reference to this builder * */ public PushClientBuilder trustedServerCertificateChain(final X509Certificate... certificates) { this.trustedServerCertificates = certificates; return this; } /** * Sets the metrics listener for the client under construction. Metrics listeners gather information that describes * the performance and behavior of a client, and are completely optional. * * @param metricsListener the metrics listener for the client under construction, or {@code null} if this client * should not report metrics to a listener * * @return a reference to this builder * */ public PushClientBuilder metricsListener(final PushClientMetricsListener metricsListener) { this.metricsListener = metricsListener; return this; } /** * Sets the maximum amount of time, in milliseconds, that the client under construction will wait to establish a * connection with the APNs server before the connection attempt is considered a failure. * * @param timeout the maximum amount of time to wait for a connection attempt to complete * * @return a reference to this builder * */ public PushClientBuilder connectionTimeout(final Duration timeout) { this.connectionTimeout = timeout; return this; } /** * Sets the amount of idle time (in milliseconds) after which the client under construction will send a PING frame * to the APNs server. By default, clients will send a PING frame after an idle period of 1 minutes. * * * @param idleInterval the amount of idle time after which the client will send a PING frame * * @return a reference to this builder * */ public PushClientBuilder idleInterval(final Duration idleInterval) { this.idleInterval = idleInterval; return this; } /** * Sets the HTTP/2 frame logger for the client under construction. HTTP/2 frame loggers log all HTTP/2 frames sent * to or from the client to the logging system of your choice via SLF4J. Frame logging is extremely verbose and is * recommended only for debugging purposes. * * @param frameLogger the frame logger to be used by the client under construction or {@code null} if the client * should not log individual HTTP/2 frames * * @return a reference to this builder * * @see SLF4J * */ public PushClientBuilder http2FrameLogger(Http2FrameLogger frameLogger) { this.frameLogger = frameLogger; return this; } /** * capacity of pooled connection channels . default 1 if not set this property. * * @param capacity * @return */ public PushClientBuilder poolCapacity(int capacity) { this.poolCapacity = capacity; return this; } public PushClient build() throws SSLException { if (this.environment == null) { throw new IllegalStateException("No APNs server address specified."); } if (this.certificate == null && this.certificatePrivateKey == null && this.signKey == null) { throw new IllegalStateException("No client credentials specified; either TLS credentials (a " + "certificate/private key) or an APNs signing key must be provided before building a client."); } else if ((this.certificate != null || this.certificatePrivateKey != null) && this.signKey != null) { throw new IllegalStateException("Clients may not have both a signing key and TLS credentials."); } final SslContext sslContext; final SslProvider sslProvider; if (OpenSsl.isAvailable()) { logger.info("Native SSL provider is available; will use native provider."); sslProvider = SslProvider.OPENSSL_REFCNT; } else { logger.info("Native SSL provider not available; will use JDK SSL provider."); sslProvider = SslProvider.JDK; } final SslContextBuilder sslContextBuilder = SslContextBuilder.forClient() .sslProvider(sslProvider) .ciphers(Http2SecurityUtil.CIPHERS, SupportedCipherSuiteFilter.INSTANCE); if (this.certificate != null && this.certificatePrivateKey != null) { sslContextBuilder.keyManager(this.certificatePrivateKey, this.certificatePrivateKeyPassword, this.certificate); } if (this.trustedServerCertificatePemFile != null) { sslContextBuilder.trustManager(this.trustedServerCertificatePemFile); } else if (this.trustedServerCertificateInputStream != null) { sslContextBuilder.trustManager(this.trustedServerCertificateInputStream); } else if (this.trustedServerCertificates != null) { sslContextBuilder.trustManager(this.trustedServerCertificates); } sslContext = sslContextBuilder.build(); try { return new PushClient(environment,topic,sslContext,signKey, tokenExpiration, connectionTimeout, idleInterval,metricsListener, frameLogger, poolCapacity ); } finally { if (sslContext instanceof ReferenceCounted) { ((ReferenceCounted) sslContext).release(); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy