pairWith method

Future<Database> pairWith(
  1. String localId,
  2. PairingCode code
)

Joins the database sponsored under code, opening it locally as localId.

Runs the PAKE with the sponsor, receives the roster key, opens the database, and waits for this device's wrapped group key to arrive by sync so the returned Database is DeviceState.ready.

Throws PairingRejected (wrong code, too many tries, or the code was already used) or PairingTimeout.

Implementation

Future<Database> pairWith(String localId, PairingCode code) async {
  final coordinator = _requirePairing();
  if (_databases.containsKey(localId)) {
    throw StateError('Database "$localId" is already open.');
  }
  final joinerKey = await identity.publicKey;
  final bundle = await coordinator.join(code, joinerPublicKey: joinerKey);

  final entryKey = '${_config.appId}/$localId';
  await _keyStore.setKey(entryKey, bundle.rosterKey);
  // The sponsor's trust state, adopted before the first sync: the roster
  // this device then receives is judged against the founder and members
  // the sponsor vouched for, not against whichever roster arrives first.
  await _keyStore.setKey(
    Database.rosterPinsKeyFor(entryKey),
    bundle.rosterPins,
  );
  // Never auto-found here: the group exists; founding a fresh key on a
  // briefly-alone install would fork it.
  final db = await _finishOpen(
    localId,
    entryKey,
    bundle.rosterKey,
    _cipherFactory(bundle.rosterKey),
    allowAutoFound: false,
  );

  for (var i = 0; i < 100 && db.deviceState != DeviceState.ready; i++) {
    await db.forceSync();
    await Future<void>.delayed(const Duration(milliseconds: 5));
    await db.refreshDeviceState();
  }
  return db;
}