establishDtlsHandshake static method

Future<bool> establishDtlsHandshake({
  1. required Bridge bridge,
  2. required DtlsData dtlsData,
  3. String decrypter(
    1. String
    )?,
})

Establish a DTLS handshake with the bridge.

Returns true if the handshake was successful, false otherwise.

The bridge parameter is the bridge to establish the handshake with.

decrypter When the old tokens are read from local storage, they are decrypted. This parameter allows you to provide your own decryption method. This will be used in addition to the default decryption method. This will be performed after the default decryption method.

May throw ExpiredAccessTokenException if trying to connect to the bridge remotely and the token is expired. If this happens, refresh the token with TokenRepo.refreshRemoteToken.

Implementation

static Future<bool> establishDtlsHandshake({
  required Bridge bridge,
  required DtlsData dtlsData,
  String Function(String)? decrypter,
}) async {
  final String? bridgeIpAddr = bridge.ipAddress;
  final String? clientKey = bridge.clientKey;
  final String? appKey = bridge.applicationKey;

  if (bridgeIpAddr == null) return false;
  if (clientKey == null) return false;
  if (appKey == null) return false;

  final String? appId = await _fetchAppId(bridgeIpAddr, appKey, decrypter);

  if (appId == null) return false;

  List<int> clientKeyBytes = [];
  for (int i = 0; i < clientKey.length; i += 2) {
    String hex = clientKey.substring(i, i + 2);
    clientKeyBytes.add(int.parse(hex, radix: 16));
  }

  final DtlsClientContext clientContext = DtlsClientContext(
    verify: true,
    withTrustedRoots: true,
    ciphers: 'PSK-AES128-GCM-SHA256',
    pskCredentialsCallback: (_) {
      return PskCredentials(
        identity: utf8.encode(appId),
        preSharedKey: clientKeyBytes,
      );
    },
  );

  List<String>? possibleIpAddresses = await _fetchIpAddr();

  if (possibleIpAddresses == null) return false;

  // Flush out old connection data.
  await dtlsData.tryDispose();

  for (String ipAddress in possibleIpAddresses) {
    try {
      dtlsData.dtlsClient = await DtlsClient.bind(ipAddress, 0);
    } catch (e) {
      continue;
    }

    try {
      dtlsData.connection = await dtlsData.dtlsClient!.connect(
        InternetAddress(bridgeIpAddr),
        2100,
        clientContext,
        timeout: const Duration(seconds: 5),
      );

      break;
    } catch (e) {
      await dtlsData.tryCloseClient();

      continue;
    }
  }

  if (dtlsData.dtlsClient == null) return false;

  if (dtlsData.connection == null) {
    await dtlsData.tryCloseClient();

    return false;
  }

  return true;
}