mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 10:25:18 +00:00
- Delete MessageRetentionService.swift - Remove retentionEnabledChannels from ChatViewModel - Remove /save command handling - Remove retention UI elements from ContentView - Remove channelRetention message type from protocol - Update documentation and tests
202 lines
7.3 KiB
Swift
202 lines
7.3 KiB
Swift
//
|
|
// NoiseIdentityPersistenceTests.swift
|
|
// bitchatTests
|
|
//
|
|
// Tests for Noise Protocol identity key persistence
|
|
//
|
|
|
|
import XCTest
|
|
@testable import bitchat
|
|
|
|
class NoiseIdentityPersistenceTests: XCTestCase {
|
|
|
|
override func setUp() {
|
|
super.setUp()
|
|
// Clean up any existing test data
|
|
cleanupTestData()
|
|
}
|
|
|
|
override func tearDown() {
|
|
// Clean up after tests
|
|
cleanupTestData()
|
|
super.tearDown()
|
|
}
|
|
|
|
private func cleanupTestData() {
|
|
// Clear any existing identity keys
|
|
_ = KeychainManager.shared.deleteIdentityKey(forKey: "noiseStaticKey")
|
|
_ = KeychainManager.shared.deleteIdentityKey(forKey: "messageRetentionKey")
|
|
|
|
// Clear any UserDefaults that might interfere
|
|
UserDefaults.standard.removeObject(forKey: "bitchat.noiseIdentityKey")
|
|
UserDefaults.standard.removeObject(forKey: "bitchat.messageRetentionKey")
|
|
UserDefaults.standard.synchronize()
|
|
}
|
|
|
|
// MARK: - Identity Persistence Tests
|
|
|
|
func testIdentityPersistsAcrossInstances() {
|
|
// Create first instance
|
|
let service1 = NoiseEncryptionService()
|
|
let fingerprint1 = service1.getIdentityFingerprint()
|
|
let publicKey1 = service1.getStaticPublicKeyData()
|
|
|
|
XCTAssertFalse(fingerprint1.isEmpty, "Fingerprint should not be empty")
|
|
XCTAssertEqual(publicKey1.count, 32, "Public key should be 32 bytes")
|
|
|
|
// Create second instance
|
|
let service2 = NoiseEncryptionService()
|
|
let fingerprint2 = service2.getIdentityFingerprint()
|
|
let publicKey2 = service2.getStaticPublicKeyData()
|
|
|
|
// Verify same identity
|
|
XCTAssertEqual(fingerprint1, fingerprint2, "Fingerprint should persist across instances")
|
|
XCTAssertEqual(publicKey1, publicKey2, "Public key should persist across instances")
|
|
}
|
|
|
|
func testIdentityNotStoredInUserDefaults() {
|
|
// Create service to generate identity
|
|
_ = NoiseEncryptionService()
|
|
|
|
// Verify identity is NOT in UserDefaults
|
|
let userDefaultsData = UserDefaults.standard.data(forKey: "bitchat.noiseIdentityKey")
|
|
XCTAssertNil(userDefaultsData, "Identity key should NOT be stored in UserDefaults")
|
|
}
|
|
|
|
func testIdentityStoredInKeychain() {
|
|
// Create service to generate identity
|
|
_ = NoiseEncryptionService()
|
|
|
|
// Verify identity IS in Keychain
|
|
let keychainData = KeychainManager.shared.getIdentityKey(forKey: "noiseStaticKey")
|
|
XCTAssertNotNil(keychainData, "Identity key should be stored in Keychain")
|
|
XCTAssertEqual(keychainData?.count, 32, "Identity key should be 32 bytes")
|
|
}
|
|
|
|
func testPanicModeClearsIdentity() {
|
|
// Create service and get initial fingerprint
|
|
let service1 = NoiseEncryptionService()
|
|
let fingerprint1 = service1.getIdentityFingerprint()
|
|
|
|
// Clear identity (panic mode)
|
|
service1.clearPersistentIdentity()
|
|
|
|
// Create new service and verify new identity
|
|
let service2 = NoiseEncryptionService()
|
|
let fingerprint2 = service2.getIdentityFingerprint()
|
|
|
|
XCTAssertNotEqual(fingerprint1, fingerprint2, "New identity should be created after panic mode")
|
|
}
|
|
|
|
func testMultipleRapidInstantiations() {
|
|
// Create multiple services rapidly
|
|
var fingerprints: [String] = []
|
|
|
|
for _ in 0..<10 {
|
|
let service = NoiseEncryptionService()
|
|
fingerprints.append(service.getIdentityFingerprint())
|
|
}
|
|
|
|
// Verify all fingerprints are the same
|
|
let firstFingerprint = fingerprints[0]
|
|
for fingerprint in fingerprints {
|
|
XCTAssertEqual(fingerprint, firstFingerprint, "All instances should have same identity")
|
|
}
|
|
}
|
|
|
|
func testKeychainAccessFailureHandling() {
|
|
// This test would require mocking KeychainManager, but we can at least
|
|
// verify the service initializes even if keychain is problematic
|
|
let service = NoiseEncryptionService()
|
|
XCTAssertFalse(service.getIdentityFingerprint().isEmpty, "Service should initialize with valid identity")
|
|
}
|
|
|
|
// MARK: - Message Retention Key Tests
|
|
// Message retention feature has been removed
|
|
|
|
// MARK: - Keychain Service Name Tests
|
|
|
|
func testKeychainServiceName() {
|
|
// Verify we're using the correct service name
|
|
let expectedService = "chat.bitchat"
|
|
|
|
// Save a test item
|
|
let testKey = "test_service_verification"
|
|
let testData = "test".data(using: .utf8)!
|
|
_ = KeychainManager.shared.saveIdentityKey(testData, forKey: testKey)
|
|
|
|
// Query directly to verify service name
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: expectedService,
|
|
kSecAttrAccount as String: "identity_\(testKey)",
|
|
kSecMatchLimit as String: kSecMatchLimitOne,
|
|
kSecReturnData as String: true
|
|
]
|
|
|
|
var result: AnyObject?
|
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
|
|
XCTAssertEqual(status, errSecSuccess, "Should find item with expected service name")
|
|
XCTAssertNotNil(result as? Data, "Should retrieve data")
|
|
|
|
// Clean up
|
|
_ = KeychainManager.shared.deleteIdentityKey(forKey: testKey)
|
|
}
|
|
|
|
// MARK: - Legacy Cleanup Tests
|
|
|
|
func testLegacyKeychainCleanup() {
|
|
// Create some legacy items with old service names
|
|
let legacyServices = [
|
|
"com.bitchat.passwords",
|
|
"com.bitchat.noise.identity",
|
|
"bitchat.keychain"
|
|
]
|
|
|
|
// Add test items with legacy service names
|
|
for service in legacyServices {
|
|
let addQuery: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: service,
|
|
kSecAttrAccount as String: "test_legacy_item",
|
|
kSecValueData as String: "test".data(using: .utf8)!
|
|
]
|
|
|
|
// Add item (ignore if already exists)
|
|
_ = SecItemAdd(addQuery as CFDictionary, nil)
|
|
}
|
|
|
|
// Run aggressive cleanup
|
|
let deletedCount = KeychainManager.shared.aggressiveCleanupLegacyItems()
|
|
|
|
// Verify items were deleted
|
|
XCTAssertGreaterThan(deletedCount, 0, "Should delete at least some legacy items")
|
|
|
|
// Verify legacy items are gone
|
|
for service in legacyServices {
|
|
let query: [String: Any] = [
|
|
kSecClass as String: kSecClassGenericPassword,
|
|
kSecAttrService as String: service,
|
|
kSecMatchLimit as String: kSecMatchLimitOne
|
|
]
|
|
|
|
var result: AnyObject?
|
|
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
|
|
|
XCTAssertEqual(status, errSecItemNotFound, "Legacy service '\(service)' should be deleted")
|
|
}
|
|
}
|
|
|
|
// MARK: - Performance Tests
|
|
|
|
func testIdentityLoadPerformance() {
|
|
// Ensure identity exists
|
|
_ = NoiseEncryptionService()
|
|
|
|
measure {
|
|
// Measure how long it takes to load identity
|
|
_ = NoiseEncryptionService()
|
|
}
|
|
}
|
|
} |