Skip to main content
Version: 5.9.0

Network settings

Network settings for connecting to the server are described by the ChatNetworkConfig model.

Initialization:

The default constructor creates a model with the standard settings:

var chatNetworkConfig = ChatNetworkConfig()

You can configure individual connection components:

  • httpConfig: REST API settings
  • wsConfig: WebSocket API settings
  • sslPinning: SSL pinning settings
Mutations after SDK initialization do not apply

ChatNetworkConfig is a struct and is passed inside ChatConfig by value. After ChatCenterUISDK(chatConfig:) is called, the SDK works with its own copy; changes to chatConfig.networkConfig or its nested fields from the integrator's side have no effect. Set all fields before passing ChatConfig to the SDK constructor. Details — SDK settings.

REST API settings (HTTPConfig)

HTTP(S) connection parameters for the REST API:

FieldTypeRequiredDescription
connectionTimeoutTimeInterval (sec)No (default 30)Idle timeout for a REST request: applied as URLRequest.timeoutInterval and covers all phases (establishing the connection + waiting for a response). Applies only to REST; for WebSocket see WSConfig.connectionTimeout
downloadTimeoutTimeInterval (sec)No (default 30)Idle timeout for a file download request: applied as URLRequest.timeoutInterval (same semantics as connectionTimeout)
uploadTimeoutTimeInterval (sec)No (default 120)Applied simultaneously as URLSessionConfiguration.timeoutIntervalForRequest (idle timeout) and timeoutIntervalForResource (overall resource load limit). This means: for the default 120, the total file upload time must not exceed 120 seconds — for large files over a slow connection, the value needs to be increased. The SDK's upload session is also hard-configured with waitsForConnectivity = true: if there is no network, the request waits for it to be restored rather than failing immediately (REST and download, in contrast, fail right away). The total wait time is still limited by uploadTimeout

WebSocket connection settings (WSConfig)

WS(S) connection parameters for real-time messages:

FieldTypeRequiredDescription
connectionTimeoutTimeInterval (sec)No (default 30)Timeout for the WebSocket upgrade request: the value is applied both as URLSessionConfiguration.timeoutIntervalForRequest and as the upgrade request's URLRequest.timeoutInterval
sendTimeoutTimeInterval (sec)No (default 20)Used simultaneously as: (1) the interval of the timer that checks the status of unsent messages (the timer works while the chat screen is open and the dialog is active; on going to background it stops); (2) the threshold after which a message in the .sending status is marked as .failed if there is no server response. If the server returned an error response over WebSocket, the message becomes .failed immediately, bypassing the timer. The "no later than after 2 × sendTimeout" guarantee applies only to the timer path

SSL pinning settings

A single certificate is a single point of failure

When using this feature, it is not recommended to install only one trusted certificate. If it is revoked or expires, the SDK will stop connecting to the server. Use additional backup certificates and update them in time.

SSLPinningConfig parameters:

FieldTypeRequiredDescription
allowUntrustedSSLCertificateBoolNo (default false)When true, the SDK accepts any server certificate without signature verification. Unsafe for production — see the :::danger below. Ignored if trustedCertificates is non-empty — pinning has priority
trustedCertificates[ChatSSLCertificate]No (default [])A list of trusted certificates in DER format. When set, the SDK fully bypasses SecTrustEvaluateWithError — hostname, validity period, and revocation checks (OCSP/CRL) are ignored. The only check is whether the public key of any certificate in the server's TLS chain (leaf, intermediate, or root) matches one of the keys in the list (public key pinning). This allows you to pin a leaf certificate as well as an intermediate/root CA — the latter survives leaf rotation without an app update
Unsafe for production

allowUntrustedSSLCertificate = true only takes effect when trustedCertificates is empty — in that case the SDK accepts any server certificate, which makes the application vulnerable to man-in-the-middle (MITM) attacks. With a non-empty trustedCertificates, the flag is ignored (pinning has priority), so there is no MITM exposure through it. Nevertheless, do not leave allowUntrustedSSLCertificate = true in production builds: if trustedCertificates turns out to be empty in some build configuration (for example, files were not found through Bundle.main.url(forResource:)), the app loses its protection without any explicit signal.

trustedCertificates replaces system TLS validation with public key verification — this works with regular CA-signed certificates, with self-signed certificates, and with certificates whose validity period has expired.

A certificate is passed as a ChatSSLCertificate model, in which a local path to the certificate is specified:

var chatNetworkConfig = ChatNetworkConfig()
if let mainCert = Bundle.main.url(forResource: "main_cert", withExtension: "cer"),
let backupCert = Bundle.main.url(forResource: "backup_cert", withExtension: "cer") {
chatNetworkConfig.sslPinning.trustedCertificates = [ChatSSLCertificate(contentsOf: mainCert), ChatSSLCertificate(contentsOf: backupCert)]
}

Certificate format

ChatSSLCertificate(contentsOf:) expects DER-encoded content — the SDK passes the file bytes directly to SecCertificateCreateWithData; the extension is not checked (.cer or .der are traditionally used, but .crt or a file without an extension will also work if the content is valid). PEM certificates (-----BEGIN CERTIFICATE-----…) are not supported — convert them before adding to the bundle:

openssl x509 -in cert.pem -outform DER -out cert.cer

Add the resulting .cer to the app bundle (Build Phases → Copy Bundle Resources). Loading via Bundle.main.url(forResource:withExtension:) will return nil if the file is missing — as in the example above, handle this explicitly: a silently missing certificate is equivalent to disabling pinning.

A corrupted or PEM certificate blocks all connections

If the file at contentsOf: exists but is not a valid DER (for example, a PEM was placed in the bundle by mistake, or the file is corrupted), ChatSSLCertificate will store an internal certificate = nil and will not throw from the constructor. The SDK writes an error message to its log stream (visible with ChatLoggerConfig(logLevel: .all) — see Logging settings), but there is no failure signal in the integrator's code.

The effect differs from the "empty trustedCertificates array" case: an array with a corrupted ChatSSLCertificate is not empty, so the SDK still enters pinning mode. Corrupted elements are skipped by the loop and do not block valid ones: if there is at least one valid ChatSSLCertificate in the array with a matching public key, the connection will be established. But if all elements are corrupted — the SDK finds no matches and rejects all TLS connections. Externally this looks like "the network is broken," not "pinning is disabled."

After adding a certificate, verify both that the connection actually establishes and that swapping the server for a known "wrong" certificate breaks the connection.

SSL error diagnostics

If the connection does not open after enabling pinning:

SymptomPossible causeWhat to check
Connection aborts during handshake (SDK log shows SSL CERTIFICATES Pinning error - server and pinned certificates are not equals)No public key from the server's TLS chain matches the public keys in trustedCertificatesEnable ChatLoggerConfig(logLevel: .all) and compare the hex values of SSL Server public key: (all certificates in the server chain) and SSL Pinned certificate public key: (those attached) — at least one pair must match. The SDK logs keys in raw format (SecKeyCopyExternalRepresentation: PKCS #1 for RSA, X9.63 for EC), so third-party commands such as openssl x509 -pubkey | openssl pkey -pubin -outform DER | openssl dgst -sha256 will produce a different hash (SubjectPublicKeyInfo) — they are not suitable for comparing with the SDK log
The connection worked, then stopped (without an app update)The server certificate was rotated, and the app does not have the new oneContact edna support; a temporary fallback is the backup certificate, if it was added in advance
nil after Bundle.main.url(forResource:)The file did not get into Copy Bundle Resources, or the name and extension were split incorrectly (forResource: "cert.cer" instead of forResource: "cert", withExtension: "cer")Check target → Build Phases → Copy Bundle Resources (the file must be in the list); check that in Bundle.main.url(forResource:withExtension:) the file name is passed without the extension and the extension is the second argument
The error appears only in the Release buildThe ATS configuration for the domain differs between Debug and Release (for example, NSAllowsArbitraryLoads: true is set only in Debug)Check NSAppTransportSecurity in Info.plist of both builds; with correct server hosts (HTTPS with valid certificates), no special ATS settings are required

Enable detailed SDK logging (ChatLoggerConfig(logLevel: .all)) — SSL handshake messages are written to the common log stream and are delivered to the ChatCenterUISDKDelegate delegate via the chatCenterUI(chatCenter:didLog:) method.

Certificate rotation

The server certificate has a validity period. To avoid an app blackout during rotation:

  1. Request the schedule from edna support — how long before expiration you will receive the new certificate.
  2. Always keep at least 2 certificates in trustedCertificates: the current one + the backup (next). When edna rotates the certificate, the new one will already be in the app's trust list.
  3. When rolling out an app version, make sure the new certificate is included in the bundle before the old one stops working on the server.
  4. Do not use allowUntrustedSSLCertificate = true in production even temporarily as a workaround — that defeats the MITM protection for the entire duration of the fix.