1package com.peachpasswords.sync23import kotlinx.coroutines.CancellationException4import org.json.JSONObject5678910111213141516171819internal suspend fun runCloudRelayInitiatorSession(20 socket: RelayBinarySocket,21 known: PairedDevice,22 rendezvousId: String,23 ourStaticPrivateKey: ByteArray,24 ourStaticPublicKey: ByteArray,25 localIdentity: LocalDeviceIdentity,26 vaultFactory: () -> SyncVaultAdapter?,27 onSyncComplete: () -> Unit,28 report: (SyncOutcomeSummary) -> Unit = {},29) {30 val responderKeyHex = known.longTermPublicKeyHex31 ?: throw IllegalArgumentException("known peer missing static key")32 val responderKey = hexToPubkey(responderKeyHex)3334 35 36 socket.send(37 JSONObject()38 .put("type", "PEACH_RECONNECT")39 .put("rendezvous_id", rendezvousId)40 .toString()41 .toByteArray(Charsets.UTF_8),42 )43 val session = noiseKKInitiator(44 ourStaticPrivateKey,45 ourStaticPublicKey,46 responderKey,47 socket::send,48 socket::receive,49 )50 51 52 53 try {54 socket.send(session.encrypt(SyncPadding.pad(encodePairIdentityFrame(localIdentity))))55 val theirIdentity = parsePairIdentityFrame(56 SyncPadding.unpad(session.decrypt(socket.receive())),57 )58 require(identityMatchesAuthenticatedPeer(known, theirIdentity, responderKey)) {59 "peer identity does not match authenticated KK key"60 }6162 val vault = vaultFactory() ?: run {63 report(SyncOutcomeSummary(reason = SyncOutcomeReason.VAULT_LOCKED))64 return65 }66 vault.bindAuthenticatedPeer(known)67 val outcome = runSyncInitiator(68 SyncSession(69 remoteStaticPublicKey = responderKey.copyOf(),70 send = { plaintext -> socket.send(session.encrypt(SyncPadding.pad(plaintext))) },71 receive = { SyncPadding.unpad(session.decrypt(socket.receive())) },72 close = { socket.close() },73 ),74 vault,75 )76 if (outcome.status == SyncOutcomeStatus.COMPLETED) {77 onSyncComplete()78 }79 report(outcome.toSummary())80 } catch (e: CancellationException) {81 throw e82 } catch (e: Exception) {83 84 85 report(SyncOutcomeSummary(reason = classifySyncError(e.message ?: e.toString()), detail = e.message))86 throw e87 } finally {88 session.close()89 }90}