runNodeHandshake function

Future<void> runNodeHandshake(
  1. HandshakeConnection connection, {
  2. required Future<Credential> credentials(
    1. Uint8List challenge
    ),
  3. required String agentVersion,
  4. Duration timeout = const Duration(seconds: 10),
})

Runs the node side of OmnyServer's in-band authentication exchange — the counterpart of the Hub's NodeConnectionAuthenticator.

Wired into NodeConfig.onHandshake, so it runs on the freshly-opened control connection before the node registers: announce, answer the Hub's challenge with a credential (a token, or the nonce signed with the node's Ed25519 key), and wait to be accepted.

Throws AuthException on rejection. The agent treats that as terminal — a revoked key is not fixed by reconnecting, and retrying would only hammer the Hub with the credential it just refused.

Implementation

Future<void> runNodeHandshake(
  omnyhub.HandshakeConnection connection, {
  required Future<Credential> Function(Uint8List challenge) credentials,
  required String agentVersion,
  Duration timeout = const Duration(seconds: 10),
}) async {
  final channel = HandshakeChannel(connection);

  channel.send(
    Hello(
      role: PeerRole.node,
      protocolVersion: ProtocolVersion.current.label,
      agentVersion: agentVersion,
    ),
  );

  final challenge = await channel.expect<AuthChallenge>(timeout: timeout);
  final credential = await credentials(decodeChallenge(challenge.nonce));
  channel.send(AuthSubmit(credential));

  // `expect` turns an auth.fail into an AuthException for us.
  await channel.expect<AuthOk>(timeout: timeout);
}