mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 14:25:20 +00:00
refactor: remove all dead legacy and migration code
- Remove unused migrateSession() functions (never called in production) - NoiseSession.migrateSession() - 13 lines - NoiseEncryptionService.migratePeerSession() - 18 lines - Test for migration functionality - 17 lines - Remove unnecessary keychain cleanup code (no legacy data existed) - cleanupLegacyKeychainItems() - 62 lines - aggressiveCleanupLegacyItems() - 72 lines - resetCleanupFlag() - 4 lines - Simplified panic mode to just use deleteAllKeychainData() Total removed: 194 lines of dead/unnecessary code Analysis revealed: - KeychainManager introduced July 5, 2025 - Cleanup code added July 15, 2025 (10 days later) - Legacy service names were never used in production - Migration functions were incomplete implementation never called - Peer ID rotation remains active (not legacy)
This commit is contained in:
@@ -296,19 +296,6 @@ class NoiseSessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
func migrateSession(from oldPeerID: String, to newPeerID: String) {
|
||||
managerQueue.sync(flags: .barrier) {
|
||||
// Check if we have a session for the old peer ID
|
||||
if let session = sessions[oldPeerID] {
|
||||
// Move the session to the new peer ID
|
||||
sessions[newPeerID] = session
|
||||
_ = sessions.removeValue(forKey: oldPeerID)
|
||||
|
||||
SecureLogger.log("Migrated Noise session from \(oldPeerID) to \(newPeerID)", category: SecureLogger.noise, level: .info)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getEstablishedSessions() -> [String: NoiseSession] {
|
||||
return managerQueue.sync {
|
||||
return sessions.filter { $0.value.isEstablished() }
|
||||
|
||||
@@ -17,73 +17,7 @@ class KeychainManager {
|
||||
private let service = "chat.bitchat"
|
||||
private let appGroup = "group.chat.bitchat"
|
||||
|
||||
private init() {
|
||||
// Clean up legacy keychain items on first run
|
||||
cleanupLegacyKeychainItems()
|
||||
}
|
||||
|
||||
private func cleanupLegacyKeychainItems() {
|
||||
// Check if we've already done cleanup
|
||||
let cleanupKey = "bitchat.keychain.cleanup.v2"
|
||||
if UserDefaults.standard.bool(forKey: cleanupKey) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// List of old service names to migrate from
|
||||
let legacyServices = [
|
||||
"com.bitchat.passwords",
|
||||
"com.bitchat.deviceidentity",
|
||||
"com.bitchat.noise.identity",
|
||||
"chat.bitchat.passwords",
|
||||
"bitchat.keychain"
|
||||
]
|
||||
|
||||
var migratedItems = 0
|
||||
|
||||
// Try to migrate identity keys
|
||||
for oldService in legacyServices {
|
||||
// Check for noise identity key
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: oldService,
|
||||
kSecAttrAccount as String: "identity_noiseStaticKey",
|
||||
kSecReturnData as String: true
|
||||
]
|
||||
|
||||
var result: AnyObject?
|
||||
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
||||
|
||||
if status == errSecSuccess, let data = result as? Data {
|
||||
// Save to new service
|
||||
if saveIdentityKey(data, forKey: "noiseStaticKey") {
|
||||
migratedItems += 1
|
||||
SecureLogger.logKeyOperation("migrate", keyType: "noiseStaticKey", success: true)
|
||||
}
|
||||
// Delete from old service
|
||||
let deleteQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: oldService,
|
||||
kSecAttrAccount as String: "identity_noiseStaticKey"
|
||||
]
|
||||
SecItemDelete(deleteQuery as CFDictionary)
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up all other legacy items
|
||||
for oldService in legacyServices {
|
||||
let deleteQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: oldService
|
||||
]
|
||||
|
||||
SecItemDelete(deleteQuery as CFDictionary)
|
||||
}
|
||||
|
||||
|
||||
// Mark cleanup as done
|
||||
UserDefaults.standard.set(true, forKey: cleanupKey)
|
||||
}
|
||||
private init() {}
|
||||
|
||||
|
||||
private func isSandboxed() -> Bool {
|
||||
@@ -240,11 +174,6 @@ class KeychainManager {
|
||||
return status == errSecSuccess || status == errSecItemNotFound
|
||||
}
|
||||
|
||||
// Force cleanup to run again (for development/testing)
|
||||
func resetCleanupFlag() {
|
||||
UserDefaults.standard.removeObject(forKey: "bitchat.keychain.cleanup.v2")
|
||||
}
|
||||
|
||||
|
||||
// Delete ALL keychain data for panic mode
|
||||
func deleteAllKeychainData() -> Bool {
|
||||
@@ -384,76 +313,4 @@ class KeychainManager {
|
||||
let key = "identity_noiseStaticKey"
|
||||
return retrieveData(forKey: key) != nil
|
||||
}
|
||||
|
||||
// Aggressive cleanup for legacy items - can be called manually
|
||||
func aggressiveCleanupLegacyItems() -> Int {
|
||||
var deletedCount = 0
|
||||
|
||||
// List of KNOWN bitchat service names from our development history
|
||||
let knownBitchatServices = [
|
||||
"com.bitchat.passwords",
|
||||
"com.bitchat.deviceidentity",
|
||||
"com.bitchat.noise.identity",
|
||||
"chat.bitchat.passwords",
|
||||
"bitchat.keychain",
|
||||
"Bitchat",
|
||||
"BitChat"
|
||||
]
|
||||
|
||||
// First, delete all items from known legacy services
|
||||
for legacyService in knownBitchatServices {
|
||||
let deleteQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: legacyService
|
||||
]
|
||||
|
||||
let status = SecItemDelete(deleteQuery as CFDictionary)
|
||||
if status == errSecSuccess {
|
||||
deletedCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
// Now search for items that have our specific account patterns with bitchat service names
|
||||
let searchQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecMatchLimit as String: kSecMatchLimitAll,
|
||||
kSecReturnAttributes as String: true
|
||||
]
|
||||
|
||||
var result: AnyObject?
|
||||
let status = SecItemCopyMatching(searchQuery as CFDictionary, &result)
|
||||
|
||||
if status == errSecSuccess, let items = result as? [[String: Any]] {
|
||||
for item in items {
|
||||
let account = item[kSecAttrAccount as String] as? String ?? ""
|
||||
let service = item[kSecAttrService as String] as? String ?? ""
|
||||
|
||||
// ONLY delete if service name contains "bitchat" somewhere
|
||||
// This ensures we never touch other apps' keychain items
|
||||
var shouldDelete = false
|
||||
|
||||
// Check if service contains "bitchat" (case insensitive) but NOT our current service
|
||||
let serviceLower = service.lowercased()
|
||||
if service != self.service && serviceLower.contains("bitchat") {
|
||||
shouldDelete = true
|
||||
}
|
||||
|
||||
if shouldDelete {
|
||||
// Build precise delete query
|
||||
let deleteQuery: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: service,
|
||||
kSecAttrAccount as String: account
|
||||
]
|
||||
|
||||
let deleteStatus = SecItemDelete(deleteQuery as CFDictionary)
|
||||
if deleteStatus == errSecSuccess {
|
||||
deletedCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deletedCount
|
||||
}
|
||||
}
|
||||
@@ -419,24 +419,6 @@ class NoiseEncryptionService {
|
||||
SecureLogger.logSecurityEvent(.sessionExpired(peerID: peerID))
|
||||
}
|
||||
|
||||
/// Migrate session when peer ID changes
|
||||
func migratePeerSession(from oldPeerID: String, to newPeerID: String, fingerprint: String) {
|
||||
// First update the fingerprint mappings
|
||||
serviceQueue.sync(flags: .barrier) {
|
||||
// Remove old mapping
|
||||
if let oldFingerprint = peerFingerprints[oldPeerID], oldFingerprint == fingerprint {
|
||||
peerFingerprints.removeValue(forKey: oldPeerID)
|
||||
}
|
||||
|
||||
// Add new mapping
|
||||
peerFingerprints[newPeerID] = fingerprint
|
||||
fingerprintToPeerID[fingerprint] = newPeerID
|
||||
}
|
||||
|
||||
// Migrate the session in session manager
|
||||
sessionManager.migrateSession(from: oldPeerID, to: newPeerID)
|
||||
}
|
||||
|
||||
// MARK: - Private Helpers
|
||||
|
||||
private func handleSessionEstablished(peerID: String, remoteStaticKey: Curve25519.KeyAgreement.PublicKey) {
|
||||
|
||||
@@ -1474,10 +1474,7 @@ class ChatViewModel: ObservableObject, BitchatDelegate {
|
||||
privateChats.removeAll()
|
||||
unreadPrivateMessages.removeAll()
|
||||
|
||||
// First run aggressive cleanup to get rid of all legacy items
|
||||
_ = KeychainManager.shared.aggressiveCleanupLegacyItems()
|
||||
|
||||
// Then delete all current keychain data
|
||||
// Delete all keychain data
|
||||
_ = KeychainManager.shared.deleteAllKeychainData()
|
||||
|
||||
// Clear UserDefaults identity fallbacks
|
||||
|
||||
@@ -226,23 +226,6 @@ final class NoiseProtocolTests: XCTestCase {
|
||||
XCTAssertEqual(decrypted, plaintext)
|
||||
}
|
||||
|
||||
func testSessionMigration() throws {
|
||||
let manager = NoiseSessionManager(localStaticKey: aliceKey)
|
||||
|
||||
// Create and establish a session
|
||||
_ = try manager.initiateHandshake(with: TestConstants.testPeerID2)
|
||||
|
||||
// Migrate to new peer ID
|
||||
let newPeerID = TestConstants.testPeerID3
|
||||
manager.migrateSession(from: TestConstants.testPeerID2, to: newPeerID)
|
||||
|
||||
// Old peer ID should not have session
|
||||
XCTAssertNil(manager.getSession(for: TestConstants.testPeerID2))
|
||||
|
||||
// New peer ID should have the session
|
||||
XCTAssertNotNil(manager.getSession(for: newPeerID))
|
||||
}
|
||||
|
||||
// MARK: - Security Tests
|
||||
|
||||
func testTamperedCiphertextDetection() throws {
|
||||
|
||||
Reference in New Issue
Block a user