| .. | .. |
|---|
| 241 | 241 | return null; |
|---|
| 242 | 242 | } |
|---|
| 243 | 243 | |
|---|
| 244 | | - /// Probe a single host:port with a TCP connection attempt (1s timeout). |
|---|
| 244 | + /// Probe a single host:port with a TLS connection attempt (1s timeout). |
|---|
| 245 | + /// Uses SecureSocket since the broker now requires TLS. |
|---|
| 245 | 246 | Future<String?> _probeHost(String host, int port) async { |
|---|
| 246 | 247 | try { |
|---|
| 247 | | - final socket = await Socket.connect(host, port, |
|---|
| 248 | | - timeout: const Duration(seconds: 1)); |
|---|
| 248 | + final socket = await SecureSocket.connect( |
|---|
| 249 | + host, |
|---|
| 250 | + port, |
|---|
| 251 | + timeout: const Duration(seconds: 1), |
|---|
| 252 | + onBadCertificate: (_) => true, // Accept self-signed cert during scan |
|---|
| 253 | + ); |
|---|
| 249 | 254 | await socket.close(); |
|---|
| 250 | 255 | return host; |
|---|
| 251 | 256 | } catch (_) { |
|---|
| .. | .. |
|---|
| 262 | 267 | // client.maxConnectionAttempts is final — can't set it |
|---|
| 263 | 268 | client.logging(on: false); |
|---|
| 264 | 269 | |
|---|
| 270 | + // TLS: broker uses a self-signed certificate. |
|---|
| 271 | + // TODO: pin the cert fingerprint once cert rotation story is defined. |
|---|
| 272 | + client.secure = true; |
|---|
| 273 | + client.securityContext = SecurityContext(withTrustedRoots: true); |
|---|
| 274 | + client.onBadCertificate = (dynamic certificate) => true; |
|---|
| 275 | + |
|---|
| 265 | 276 | client.onConnected = _onConnected; |
|---|
| 266 | 277 | client.onDisconnected = _onDisconnected; |
|---|
| 267 | 278 | client.onAutoReconnect = _onAutoReconnect; |
|---|