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 sendSyncFrame(55 encodePairIdentityFrame(localIdentity),56 session::encrypt,57 socket::send,58 )59 val theirIdentity = parsePairIdentityFrame(60 receiveSyncFrame(socket::receive, session::decrypt),61 )62 require(identityMatchesAuthenticatedPeer(known, theirIdentity, responderKey)) {63 "peer identity does not match authenticated KK key"64 }6566 val vault = vaultFactory() ?: run {67 report(SyncOutcomeSummary(reason = SyncOutcomeReason.VAULT_LOCKED))68 return69 }70 vault.bindAuthenticatedPeer(known)71 val outcome = runSyncInitiator(72 SyncSession(73 remoteStaticPublicKey = responderKey.copyOf(),74 send = { plaintext -> sendSyncFrame(plaintext, session::encrypt, socket::send) },75 receive = { receiveSyncFrame(socket::receive, session::decrypt) },76 close = { socket.close() },77 ),78 vault,79 )80 if (outcome.status == SyncOutcomeStatus.COMPLETED) {81 onSyncComplete()82 }83 report(outcome.toSummary())84 } catch (e: CancellationException) {85 throw e86 } catch (e: Exception) {87 88 89 report(SyncOutcomeSummary(reason = classifySyncError(e.message ?: e.toString()), detail = e.message))90 throw e91 } finally {92 session.close()93 }94}