mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 00:25:20 +00:00
216 lines
6.6 KiB
Kotlin
216 lines
6.6 KiB
Kotlin
package com.bitchat.android.noise
|
|
|
|
import android.util.Log
|
|
import java.util.concurrent.ConcurrentHashMap
|
|
|
|
/**
|
|
* SIMPLIFIED Noise session manager - focuses on core functionality only
|
|
*/
|
|
class NoiseSessionManager(
|
|
private val localStaticPrivateKey: ByteArray,
|
|
private val localStaticPublicKey: ByteArray
|
|
) {
|
|
|
|
companion object {
|
|
private const val TAG = "NoiseSessionManager"
|
|
}
|
|
|
|
private val sessions = ConcurrentHashMap<String, NoiseSession>()
|
|
|
|
// Callbacks
|
|
var onSessionEstablished: ((String, ByteArray) -> Unit)? = null
|
|
var onSessionFailed: ((String, Throwable) -> Unit)? = null
|
|
|
|
// MARK: - Simple Session Management
|
|
|
|
/**
|
|
* Add new session for a peer
|
|
*/
|
|
fun addSession(peerID: String, session: NoiseSession) {
|
|
sessions[peerID] = session
|
|
}
|
|
|
|
/**
|
|
* Get existing session for a peer
|
|
*/
|
|
fun getSession(peerID: String): NoiseSession? {
|
|
val session = sessions[peerID]
|
|
return session
|
|
}
|
|
|
|
/**
|
|
* Remove session for a peer
|
|
*/
|
|
fun removeSession(peerID: String) {
|
|
sessions[peerID]?.destroy()
|
|
sessions.remove(peerID)
|
|
}
|
|
|
|
/**
|
|
* SIMPLIFIED: Initiate handshake - no tie breaker, just start
|
|
*/
|
|
fun initiateHandshake(peerID: String): ByteArray {
|
|
Log.i(TAG, "Starting Noise handshake with $peerID")
|
|
|
|
// Remove any existing session first
|
|
removeSession(peerID)
|
|
|
|
// Create new session as initiator
|
|
val session = NoiseSession(
|
|
peerID = peerID,
|
|
isInitiator = true,
|
|
localStaticPrivateKey = localStaticPrivateKey,
|
|
localStaticPublicKey = localStaticPublicKey
|
|
)
|
|
addSession(peerID, session)
|
|
|
|
try {
|
|
return session.startHandshake()
|
|
} catch (e: Exception) {
|
|
sessions.remove(peerID)
|
|
Log.e(TAG, "Failed to start Noise handshake with $peerID: ${e.message}")
|
|
throw e
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle incoming handshake message
|
|
*/
|
|
fun processHandshakeMessage(peerID: String, message: ByteArray): ByteArray? {
|
|
try {
|
|
var session = getSession(peerID)
|
|
|
|
// If no session exists, create one as responder
|
|
if (session == null) {
|
|
Log.i(TAG, "Responding to Noise handshake from $peerID")
|
|
session = NoiseSession(
|
|
peerID = peerID,
|
|
isInitiator = false,
|
|
localStaticPrivateKey = localStaticPrivateKey,
|
|
localStaticPublicKey = localStaticPublicKey
|
|
)
|
|
addSession(peerID, session)
|
|
}
|
|
|
|
// Process handshake message
|
|
val response = session.processHandshakeMessage(message)
|
|
|
|
// Check if session is established
|
|
if (session.isEstablished()) {
|
|
Log.i(TAG, "Noise session established with $peerID")
|
|
val remoteStaticKey = session.getRemoteStaticPublicKey()
|
|
if (remoteStaticKey != null) {
|
|
onSessionEstablished?.invoke(peerID, remoteStaticKey)
|
|
}
|
|
}
|
|
|
|
return response
|
|
|
|
} catch (e: Exception) {
|
|
Log.e(TAG, "Handshake failed with $peerID: ${e.message}")
|
|
sessions.remove(peerID)
|
|
onSessionFailed?.invoke(peerID, e)
|
|
throw e
|
|
}
|
|
}
|
|
|
|
/**
|
|
* SIMPLIFIED: Encrypt data
|
|
*/
|
|
fun encrypt(data: ByteArray, peerID: String): ByteArray {
|
|
val session = getSession(peerID) ?: throw IllegalStateException("No session found for $peerID")
|
|
if (!session.isEstablished()) {
|
|
throw IllegalStateException("Session not established with $peerID")
|
|
}
|
|
return session.encrypt(data)
|
|
}
|
|
|
|
/**
|
|
* SIMPLIFIED: Decrypt data
|
|
*/
|
|
fun decrypt(encryptedData: ByteArray, peerID: String): ByteArray {
|
|
val session = getSession(peerID)
|
|
if (session == null) {
|
|
throw IllegalStateException("No session found for $peerID")
|
|
}
|
|
if (!session.isEstablished()) {
|
|
throw IllegalStateException("Session not established with $peerID")
|
|
}
|
|
return session.decrypt(encryptedData)
|
|
}
|
|
|
|
/**
|
|
* Check if session is established with peer
|
|
*/
|
|
fun hasEstablishedSession(peerID: String): Boolean {
|
|
return getSession(peerID)?.isEstablished() ?: false
|
|
}
|
|
|
|
/**
|
|
* Get session state for a peer (for UI state display)
|
|
*/
|
|
fun getSessionState(peerID: String): NoiseSession.NoiseSessionState {
|
|
return getSession(peerID)?.getState() ?: NoiseSession.NoiseSessionState.Uninitialized
|
|
}
|
|
|
|
/**
|
|
* Get remote static public key for a peer (if session established)
|
|
*/
|
|
fun getRemoteStaticKey(peerID: String): ByteArray? {
|
|
return getSession(peerID)?.getRemoteStaticPublicKey()
|
|
}
|
|
|
|
/**
|
|
* Get handshake hash for channel binding (if session established)
|
|
*/
|
|
fun getHandshakeHash(peerID: String): ByteArray? {
|
|
return getSession(peerID)?.getHandshakeHash()
|
|
}
|
|
|
|
/**
|
|
* Get sessions that need rekeying based on time or message count
|
|
*/
|
|
fun getSessionsNeedingRekey(): List<String> {
|
|
return sessions.entries
|
|
.filter { (_, session) ->
|
|
session.isEstablished() && session.needsRekey()
|
|
}
|
|
.map { it.key }
|
|
}
|
|
|
|
/**
|
|
* Get debug information
|
|
*/
|
|
fun getDebugInfo(): String = buildString {
|
|
appendLine("=== Noise Session Manager Debug ===")
|
|
appendLine("Active sessions: ${sessions.size}")
|
|
appendLine("")
|
|
|
|
if (sessions.isNotEmpty()) {
|
|
appendLine("Sessions:")
|
|
sessions.forEach { (peerID, session) ->
|
|
appendLine(" $peerID: ${session.getState()}")
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shutdown manager and clean up all sessions
|
|
*/
|
|
fun shutdown() {
|
|
sessions.values.forEach { it.destroy() }
|
|
sessions.clear()
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Session-related errors
|
|
*/
|
|
sealed class NoiseSessionError(message: String, cause: Throwable? = null) : Exception(message, cause) {
|
|
object SessionNotFound : NoiseSessionError("Session not found")
|
|
object SessionNotEstablished : NoiseSessionError("Session not established")
|
|
object InvalidState : NoiseSessionError("Session in invalid state")
|
|
object HandshakeFailed : NoiseSessionError("Handshake failed")
|
|
object AlreadyEstablished : NoiseSessionError("Session already established")
|
|
}
|