mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 06:45:19 +00:00
Refactor fingerprint manager (#185)
* centralized fingerprint manager * centralized fingerprintmanager * update fingerprint only if no collision
This commit is contained in:
@@ -66,7 +66,7 @@ class BluetoothMeshService(private val context: Context) {
|
||||
// Wire up PacketProcessor reference for recursive handling in MessageHandler
|
||||
messageHandler.packetProcessor = packetProcessor
|
||||
sendPeriodicBroadcastAnnounce()
|
||||
//startPeriodicDebugLogging()
|
||||
startPeriodicDebugLogging()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,9 +126,6 @@ class BluetoothMeshService(private val context: Context) {
|
||||
// SecurityManager delegate for key exchange notifications
|
||||
securityManager.delegate = object : SecurityManagerDelegate {
|
||||
override fun onKeyExchangeCompleted(peerID: String, peerPublicKeyData: ByteArray, receivedAddress: String?) {
|
||||
// Notify delegate about key exchange completion so it can register peer fingerprint
|
||||
delegate?.registerPeerPublicKey(peerID, peerPublicKeyData)
|
||||
|
||||
receivedAddress?.let { address ->
|
||||
connectionManager.addressPeerMap[address] = peerID
|
||||
}
|
||||
@@ -259,19 +256,21 @@ class BluetoothMeshService(private val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun updatePeerIDBinding(newPeerID: String, fingerprint: String, nickname: String,
|
||||
override fun updatePeerIDBinding(newPeerID: String, nickname: String,
|
||||
publicKey: ByteArray, previousPeerID: String?) {
|
||||
|
||||
Log.d(TAG, "Updating peer ID binding: $newPeerID (was: $previousPeerID) with nickname: $nickname and public key: ${publicKey.toHexString().take(16)}...")
|
||||
// Update peer mapping in the PeerManager for peer ID rotation support
|
||||
peerManager.addOrUpdatePeer(newPeerID, nickname)
|
||||
|
||||
// Store fingerprint for the peer via centralized fingerprint manager
|
||||
val fingerprint = peerManager.storeFingerprintForPeer(newPeerID, publicKey)
|
||||
|
||||
// If there was a previous peer ID, remove it to avoid duplicates
|
||||
previousPeerID?.let { oldPeerID ->
|
||||
peerManager.removePeer(oldPeerID)
|
||||
}
|
||||
|
||||
// Register the public key with the delegate (ChatViewModel)
|
||||
delegate?.registerPeerPublicKey(newPeerID, publicKey)
|
||||
|
||||
Log.d(TAG, "Updated peer ID binding: $newPeerID (was: $previousPeerID), fingerprint: ${fingerprint.take(16)}...")
|
||||
}
|
||||
|
||||
@@ -794,7 +793,7 @@ class BluetoothMeshService(private val context: Context) {
|
||||
* Get peer fingerprint for identity management
|
||||
*/
|
||||
fun getPeerFingerprint(peerID: String): String? {
|
||||
return encryptionService.getPeerFingerprint(peerID)
|
||||
return peerManager.getFingerprintForPeer(peerID)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -853,6 +852,8 @@ class BluetoothMeshService(private val context: Context) {
|
||||
appendLine()
|
||||
appendLine(peerManager.getDebugInfo(connectionManager.addressPeerMap))
|
||||
appendLine()
|
||||
appendLine(peerManager.getFingerprintDebugInfo())
|
||||
appendLine()
|
||||
appendLine(fragmentManager.getDebugInfo())
|
||||
appendLine()
|
||||
appendLine(securityManager.getDebugInfo())
|
||||
@@ -910,5 +911,5 @@ interface BluetoothMeshDelegate {
|
||||
fun decryptChannelMessage(encryptedContent: ByteArray, channel: String): String?
|
||||
fun getNickname(): String?
|
||||
fun isFavorite(peerID: String): Boolean
|
||||
fun registerPeerPublicKey(peerID: String, publicKeyData: ByteArray)
|
||||
// registerPeerPublicKey REMOVED - fingerprints now handled centrally in PeerManager
|
||||
}
|
||||
|
||||
@@ -138,7 +138,6 @@ class MessageHandler(private val myPeerID: String) {
|
||||
// Update peer binding in the delegate (ChatViewModel/BluetoothMeshService)
|
||||
delegate?.updatePeerIDBinding(
|
||||
newPeerID = announcement.peerID,
|
||||
fingerprint = announcement.fingerprint ?: "",
|
||||
nickname = announcement.nickname,
|
||||
publicKey = announcement.publicKey,
|
||||
previousPeerID = announcement.previousPeerID
|
||||
@@ -409,7 +408,7 @@ interface MessageHandlerDelegate {
|
||||
// Noise protocol operations
|
||||
fun hasNoiseSession(peerID: String): Boolean
|
||||
fun initiateNoiseHandshake(peerID: String)
|
||||
fun updatePeerIDBinding(newPeerID: String, fingerprint: String, nickname: String,
|
||||
fun updatePeerIDBinding(newPeerID: String, nickname: String,
|
||||
publicKey: ByteArray, previousPeerID: String?)
|
||||
|
||||
// Message operations
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
package com.bitchat.android.mesh
|
||||
|
||||
import android.util.Log
|
||||
import java.security.MessageDigest
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* Centralized peer fingerprint management singleton
|
||||
*
|
||||
* This class manages all peer fingerprint storage and retrieval operations,
|
||||
* providing a single source of truth for peer identity across the entire application.
|
||||
*
|
||||
* Fingerprints are SHA-256 hashes of peer static public keys and are only stored
|
||||
* after successful Noise handshake session establishment.
|
||||
*
|
||||
* Key Design Principles:
|
||||
* - Thread-safe operations using ConcurrentHashMap
|
||||
* - Bidirectional mapping (peerID ↔ fingerprint)
|
||||
* - Support for peer ID rotation while maintaining persistent identity
|
||||
* - Centralized logging for debugging identity management
|
||||
*/
|
||||
class PeerFingerprintManager private constructor() {
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PeerFingerprintManager"
|
||||
|
||||
@Volatile
|
||||
private var INSTANCE: PeerFingerprintManager? = null
|
||||
|
||||
/**
|
||||
* Get the singleton instance
|
||||
*/
|
||||
fun getInstance(): PeerFingerprintManager {
|
||||
return INSTANCE ?: synchronized(this) {
|
||||
INSTANCE ?: PeerFingerprintManager().also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bidirectional mapping for efficient lookups
|
||||
private val peerIDToFingerprint = ConcurrentHashMap<String, String>() // peerID -> fingerprint
|
||||
private val fingerprintToPeerID = ConcurrentHashMap<String, String>() // fingerprint -> current peerID
|
||||
|
||||
// MARK: - Fingerprint Storage (Only called after successful Noise handshake)
|
||||
|
||||
/**
|
||||
* Store fingerprint mapping after successful Noise handshake session establishment
|
||||
* This is the ONLY place where fingerprints should be stored
|
||||
*
|
||||
* @param peerID The peer's current ID
|
||||
* @param publicKey The peer's static public key from Noise handshake
|
||||
*/
|
||||
fun storeFingerprintForPeer(peerID: String, publicKey: ByteArray): String {
|
||||
// get existing fingerprint for this peer and compare
|
||||
val existingFingerprint = getFingerprintForPeer(peerID)
|
||||
val fingerprint = calculateFingerprint(publicKey)
|
||||
|
||||
if (existingFingerprint != null && existingFingerprint != fingerprint) {
|
||||
Log.w(TAG, "Fingerprint mismatch for peer $peerID: $existingFingerprint != $fingerprint")
|
||||
throw IllegalStateException("Fingerprint mismatch for peer $peerID: $existingFingerprint != $fingerprint")
|
||||
}
|
||||
|
||||
// Store bidirectional mapping
|
||||
peerIDToFingerprint[peerID] = fingerprint
|
||||
fingerprintToPeerID[fingerprint] = peerID
|
||||
|
||||
Log.d(TAG, "Stored fingerprint for peer $peerID: ${fingerprint.take(16)}...")
|
||||
return fingerprint
|
||||
}
|
||||
|
||||
/**
|
||||
* Update peer ID mapping while preserving fingerprint identity
|
||||
* Used for peer ID rotation - when a peer changes their ID but maintains the same static key
|
||||
*
|
||||
* @param oldPeerID The previous peer ID (nullable if this is a fresh mapping)
|
||||
* @param newPeerID The new peer ID
|
||||
* @param fingerprint The persistent fingerprint (should match existing one)
|
||||
*/
|
||||
fun updatePeerIDMapping(oldPeerID: String?, newPeerID: String, fingerprint: String) {
|
||||
if (newPeerID.isBlank()) {
|
||||
Log.w(TAG, "Attempted to update mapping with blank newPeerID")
|
||||
return
|
||||
}
|
||||
|
||||
if (fingerprint.isBlank()) {
|
||||
Log.w(TAG, "Attempted to update mapping with blank fingerprint")
|
||||
return
|
||||
}
|
||||
|
||||
// Remove old mapping if exists
|
||||
oldPeerID?.takeIf { it.isNotBlank() }?.let { oldID ->
|
||||
val removedFingerprint = peerIDToFingerprint.remove(oldID)
|
||||
if (removedFingerprint != null && removedFingerprint == fingerprint) {
|
||||
Log.d(TAG, "Removed old mapping: $oldID -> ${removedFingerprint.take(16)}...")
|
||||
}
|
||||
}
|
||||
|
||||
// Add new mapping
|
||||
peerIDToFingerprint[newPeerID] = fingerprint
|
||||
fingerprintToPeerID[fingerprint] = newPeerID
|
||||
|
||||
Log.d(TAG, "Updated peer ID mapping: $newPeerID (was: $oldPeerID), fingerprint: ${fingerprint.take(16)}...")
|
||||
}
|
||||
|
||||
// MARK: - Fingerprint Retrieval
|
||||
|
||||
/**
|
||||
* Get fingerprint for a specific peer ID
|
||||
*
|
||||
* @param peerID The peer ID to look up
|
||||
* @return The fingerprint if found, null otherwise
|
||||
*/
|
||||
fun getFingerprintForPeer(peerID: String): String? {
|
||||
if (peerID.isBlank()) return null
|
||||
return peerIDToFingerprint[peerID]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current peer ID for a specific fingerprint
|
||||
*
|
||||
* @param fingerprint The fingerprint to look up
|
||||
* @return The current peer ID if found, null otherwise
|
||||
*/
|
||||
fun getPeerIDForFingerprint(fingerprint: String): String? {
|
||||
if (fingerprint.isBlank()) return null
|
||||
return fingerprintToPeerID[fingerprint]
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have a fingerprint for a specific peer
|
||||
*
|
||||
* @param peerID The peer ID to check
|
||||
* @return True if we have a fingerprint for this peer, false otherwise
|
||||
*/
|
||||
fun hasFingerprintForPeer(peerID: String): Boolean {
|
||||
return getFingerprintForPeer(peerID) != null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all current peer ID to fingerprint mappings
|
||||
*
|
||||
* @return Immutable copy of all mappings
|
||||
*/
|
||||
fun getAllPeerFingerprints(): Map<String, String> {
|
||||
return peerIDToFingerprint.toMap()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all current fingerprint to peer ID mappings
|
||||
*
|
||||
* @return Immutable copy of all reverse mappings
|
||||
*/
|
||||
fun getAllFingerprintMappings(): Map<String, String> {
|
||||
return fingerprintToPeerID.toMap()
|
||||
}
|
||||
|
||||
// MARK: - Peer Management
|
||||
|
||||
/**
|
||||
* Remove all mappings for a specific peer (called when peer disconnects)
|
||||
*
|
||||
* @param peerID The peer ID to remove
|
||||
*/
|
||||
fun removePeer(peerID: String) {
|
||||
if (peerID.isBlank()) return
|
||||
|
||||
val fingerprint = peerIDToFingerprint.remove(peerID)
|
||||
if (fingerprint != null) {
|
||||
fingerprintToPeerID.remove(fingerprint)
|
||||
Log.d(TAG, "Removed peer mappings for $peerID: ${fingerprint.take(16)}...")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all mappings for a specific fingerprint
|
||||
*
|
||||
* @param fingerprint The fingerprint to remove
|
||||
*/
|
||||
fun removeFingerprint(fingerprint: String) {
|
||||
if (fingerprint.isBlank()) return
|
||||
|
||||
val peerID = fingerprintToPeerID.remove(fingerprint)
|
||||
if (peerID != null) {
|
||||
peerIDToFingerprint.remove(peerID)
|
||||
Log.d(TAG, "Removed fingerprint mappings for ${fingerprint.take(16)}...: $peerID")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all fingerprint mappings (used for emergency clear/panic mode)
|
||||
*/
|
||||
fun clearAllFingerprints() {
|
||||
val count = peerIDToFingerprint.size
|
||||
peerIDToFingerprint.clear()
|
||||
fingerprintToPeerID.clear()
|
||||
Log.d(TAG, "Cleared all fingerprint mappings ($count entries)")
|
||||
}
|
||||
|
||||
// MARK: - Utility Functions
|
||||
|
||||
/**
|
||||
* Calculate SHA-256 fingerprint from public key
|
||||
*
|
||||
* @param publicKey The peer's static public key
|
||||
* @return The hex-encoded SHA-256 hash
|
||||
*/
|
||||
private fun calculateFingerprint(publicKey: ByteArray): String {
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
val hash = digest.digest(publicKey)
|
||||
return hash.joinToString("") { "%02x".format(it) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Get debug information about current fingerprint mappings
|
||||
*
|
||||
* @return Debug string with mapping counts and summary
|
||||
*/
|
||||
fun getDebugInfo(): String {
|
||||
return buildString {
|
||||
appendLine("=== PeerFingerprintManager Debug Info ===")
|
||||
appendLine("Total mappings: ${peerIDToFingerprint.size}")
|
||||
|
||||
if (peerIDToFingerprint.isNotEmpty()) {
|
||||
appendLine("Peer ID -> Fingerprint mappings:")
|
||||
peerIDToFingerprint.forEach { (peerID, fingerprint) ->
|
||||
appendLine(" $peerID -> ${fingerprint.take(16)}...")
|
||||
}
|
||||
} else {
|
||||
appendLine("No fingerprint mappings stored")
|
||||
}
|
||||
|
||||
// Verify bidirectional mapping consistency
|
||||
val inconsistentMappings = mutableListOf<String>()
|
||||
peerIDToFingerprint.forEach { (peerID, fingerprint) ->
|
||||
val reversePeerID = fingerprintToPeerID[fingerprint]
|
||||
if (reversePeerID != peerID) {
|
||||
inconsistentMappings.add("$peerID -> $fingerprint -> $reversePeerID")
|
||||
}
|
||||
}
|
||||
|
||||
if (inconsistentMappings.isNotEmpty()) {
|
||||
appendLine("⚠️ INCONSISTENT MAPPINGS DETECTED:")
|
||||
inconsistentMappings.forEach { appendLine(" $it") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,10 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
/**
|
||||
* Manages active peers, nicknames, and RSSI tracking
|
||||
* Manages active peers, nicknames, RSSI tracking, and peer fingerprints
|
||||
* Extracted from BluetoothMeshService for better separation of concerns
|
||||
*
|
||||
* Now includes centralized peer fingerprint management via PeerFingerprintManager singleton
|
||||
*/
|
||||
class PeerManager {
|
||||
|
||||
@@ -25,6 +27,9 @@ class PeerManager {
|
||||
private val announcedPeers = CopyOnWriteArrayList<String>()
|
||||
private val announcedToPeers = CopyOnWriteArrayList<String>()
|
||||
|
||||
// Centralized fingerprint management
|
||||
private val fingerprintManager = PeerFingerprintManager.getInstance()
|
||||
|
||||
// Delegate for callbacks
|
||||
var delegate: PeerManagerDelegate? = null
|
||||
|
||||
@@ -81,7 +86,7 @@ class PeerManager {
|
||||
notifyPeerListUpdate()
|
||||
return true
|
||||
}
|
||||
|
||||
Log.d(TAG, "Updated peer: $peerID ($nickname)")
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -95,6 +100,9 @@ class PeerManager {
|
||||
announcedPeers.remove(peerID)
|
||||
announcedToPeers.remove(peerID)
|
||||
|
||||
// Also remove fingerprint mappings
|
||||
fingerprintManager.removePeer(peerID)
|
||||
|
||||
if (notifyDelegate && nickname != null) {
|
||||
delegate?.onPeerDisconnected(nickname)
|
||||
notifyPeerListUpdate()
|
||||
@@ -177,6 +185,10 @@ class PeerManager {
|
||||
peerRSSI.clear()
|
||||
announcedPeers.clear()
|
||||
announcedToPeers.clear()
|
||||
|
||||
// Also clear fingerprint mappings
|
||||
fingerprintManager.clearAllFingerprints()
|
||||
|
||||
notifyPeerListUpdate()
|
||||
}
|
||||
|
||||
@@ -264,6 +276,83 @@ class PeerManager {
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Fingerprint Management (Centralized)
|
||||
|
||||
/**
|
||||
* Store fingerprint for a peer after successful Noise handshake
|
||||
* This should only be called when a Noise session is established
|
||||
*
|
||||
* @param peerID The peer's ID
|
||||
* @param publicKey The peer's static public key from Noise handshake
|
||||
*/
|
||||
fun storeFingerprintForPeer(peerID: String, publicKey: ByteArray): String {
|
||||
return fingerprintManager.storeFingerprintForPeer(peerID, publicKey)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update peer ID mapping for peer ID rotation
|
||||
*
|
||||
* @param oldPeerID The previous peer ID (nullable)
|
||||
* @param newPeerID The new peer ID
|
||||
* @param fingerprint The persistent fingerprint
|
||||
*/
|
||||
fun updatePeerIDMapping(oldPeerID: String?, newPeerID: String, fingerprint: String) {
|
||||
fingerprintManager.updatePeerIDMapping(oldPeerID, newPeerID, fingerprint)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fingerprint for a specific peer
|
||||
*
|
||||
* @param peerID The peer ID to look up
|
||||
* @return The fingerprint if found, null otherwise
|
||||
*/
|
||||
fun getFingerprintForPeer(peerID: String): String? {
|
||||
return fingerprintManager.getFingerprintForPeer(peerID)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current peer ID for a specific fingerprint
|
||||
*
|
||||
* @param fingerprint The fingerprint to look up
|
||||
* @return The current peer ID if found, null otherwise
|
||||
*/
|
||||
fun getPeerIDForFingerprint(fingerprint: String): String? {
|
||||
return fingerprintManager.getPeerIDForFingerprint(fingerprint)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have a fingerprint for a specific peer
|
||||
*
|
||||
* @param peerID The peer ID to check
|
||||
* @return True if we have a fingerprint for this peer, false otherwise
|
||||
*/
|
||||
fun hasFingerprintForPeer(peerID: String): Boolean {
|
||||
return fingerprintManager.hasFingerprintForPeer(peerID)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all current peer ID to fingerprint mappings
|
||||
*
|
||||
* @return Immutable copy of all mappings
|
||||
*/
|
||||
fun getAllPeerFingerprints(): Map<String, String> {
|
||||
return fingerprintManager.getAllPeerFingerprints()
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all fingerprint mappings (used for emergency clear)
|
||||
*/
|
||||
fun clearAllFingerprints() {
|
||||
fingerprintManager.clearAllFingerprints()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fingerprint manager debug info
|
||||
*/
|
||||
fun getFingerprintDebugInfo(): String {
|
||||
return fingerprintManager.getDebugInfo()
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the manager
|
||||
*/
|
||||
|
||||
@@ -146,46 +146,46 @@ class SecurityManager(private val encryptionService: EncryptionService, private
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle key exchange packet
|
||||
*/
|
||||
suspend fun handleKeyExchange(routed: RoutedPacket): Boolean {
|
||||
val packet = routed.packet
|
||||
val peerID = routed.peerID ?: "unknown"
|
||||
|
||||
if (peerID == myPeerID) return false
|
||||
|
||||
if (packet.payload.isEmpty()) {
|
||||
Log.w(TAG, "Key exchange packet has empty payload")
|
||||
return false
|
||||
}
|
||||
|
||||
// Prevent duplicate key exchange processing
|
||||
val exchangeKey = "$peerID-${packet.payload.sliceArray(0 until minOf(16, packet.payload.size)).contentHashCode()}"
|
||||
|
||||
if (processedKeyExchanges.contains(exchangeKey)) {
|
||||
Log.d(TAG, "Already processed key exchange: $exchangeKey")
|
||||
return false
|
||||
}
|
||||
|
||||
processedKeyExchanges.add(exchangeKey)
|
||||
|
||||
try {
|
||||
// Process the key exchange
|
||||
encryptionService.addPeerPublicKey(peerID, packet.payload)
|
||||
|
||||
Log.d(TAG, "Successfully processed key exchange from $peerID")
|
||||
|
||||
// Notify delegate
|
||||
delegate?.onKeyExchangeCompleted(peerID, packet.payload, routed.relayAddress)
|
||||
|
||||
return true
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Failed to process key exchange from $peerID: ${e.message}")
|
||||
return false
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * Handle key exchange packet
|
||||
// */
|
||||
// suspend fun handleKeyExchange(routed: RoutedPacket): Boolean {
|
||||
// val packet = routed.packet
|
||||
// val peerID = routed.peerID ?: "unknown"
|
||||
//
|
||||
// if (peerID == myPeerID) return false
|
||||
//
|
||||
// if (packet.payload.isEmpty()) {
|
||||
// Log.w(TAG, "Key exchange packet has empty payload")
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// // Prevent duplicate key exchange processing
|
||||
// val exchangeKey = "$peerID-${packet.payload.sliceArray(0 until minOf(16, packet.payload.size)).contentHashCode()}"
|
||||
//
|
||||
// if (processedKeyExchanges.contains(exchangeKey)) {
|
||||
// Log.d(TAG, "Already processed key exchange: $exchangeKey")
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// processedKeyExchanges.add(exchangeKey)
|
||||
//
|
||||
// try {
|
||||
// // Process the key exchange
|
||||
// encryptionService.addPeerPublicKey(peerID, packet.payload)
|
||||
//
|
||||
// Log.d(TAG, "Successfully processed key exchange from $peerID")
|
||||
//
|
||||
// // Notify delegate
|
||||
// delegate?.onKeyExchangeCompleted(peerID, packet.payload, routed.relayAddress)
|
||||
//
|
||||
// return true
|
||||
//
|
||||
// } catch (e: Exception) {
|
||||
// Log.e(TAG, "Failed to process key exchange from $peerID: ${e.message}")
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Verify packet signature
|
||||
|
||||
Reference in New Issue
Block a user