Signal-iOS/SignalServiceKit/tests/Messages/SessionStoreTest.swift
2025-07-03 11:27:17 -07:00

119 lines
5.1 KiB
Swift

//
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import XCTest
import LibSignalClient
@testable import SignalServiceKit
class SessionStoreTest: SSKBaseTest {
func testLegacySessionIsDropped() {
@objc(FakeLegacySession) class FakeLegacySession: NSObject, NSCoding {
override init() {
}
required init?(coder: NSCoder) {
fatalError("should never be deserialized")
}
func encode(with coder: NSCoder) {
// no properties
}
}
// We have to use the database-based KeyValueStore to test this
// because the in-memory one skips the archiving step.
let sessionStore = SSKSessionStore(for: .aci, recipientIdFinder: DependenciesBridge.shared.recipientIdFinder)
let recipient = write {
DependenciesBridge.shared.recipientFetcher.fetchOrCreate(serviceId: Aci.randomForTesting(), tx: $0)
}
// First make sure that if we write a "valid" session, it can be read.
let singleValidSessionData = try! NSKeyedArchiver.archivedData(withRootObject: [1: Data()], requiringSecureCoding: true)
write {
sessionStore.keyValueStoreForTesting.setData(singleValidSessionData, key: recipient.uniqueId, transaction: $0)
}
read {
XCTAssertTrue(sessionStore.mightContainSession(for: recipient, tx: $0))
XCTAssertNotNil(try! sessionStore.loadSession(for: recipient.aci!, deviceId: DeviceId(validating: 1)!, tx: $0))
}
// Then imitate a session store with a mix of legacy and modern sessions.
let sessions: NSDictionary = [1: FakeLegacySession(), 2: Data()]
let archiver = NSKeyedArchiver(requiringSecureCoding: false)
archiver.setClassName("SSKLegacySessionClassThatNoLongerExists", for: FakeLegacySession.self)
archiver.encode(sessions, forKey: NSKeyedArchiveRootObjectKey)
write {
sessionStore.keyValueStoreForTesting.setData(archiver.encodedData, key: recipient.uniqueId, transaction: $0)
}
read {
// There's something in the store...
XCTAssertTrue(sessionStore.mightContainSession(for: recipient, tx: $0))
// ...but it turns into nil on load.
XCTAssertNil(try! sessionStore.loadSession(for: recipient.aci!, deviceId: DeviceId(validating: 2)!, tx: $0))
}
}
}
class SessionStoreTest2: XCTestCase {
func testMaxUnacknowledgedSessionAge() throws {
let bob_address = try ProtocolAddress(name: "+14155550100", deviceId: 1)
let alice_store = InMemorySignalProtocolStore()
let bob_store = InMemorySignalProtocolStore()
let bob_pre_key = PrivateKey.generate()
let bob_signed_pre_key = PrivateKey.generate()
let bob_signed_pre_key_public = bob_signed_pre_key.publicKey.serialize()
let bob_kyber_pre_key = KEMKeyPair.generate()
let bob_kyber_pre_key_public = bob_kyber_pre_key.publicKey.serialize()
let bob_identity_key = try! bob_store.identityKeyPair(context: NullContext())
let bob_signed_pre_key_signature = bob_identity_key.privateKey.generateSignature(message: bob_signed_pre_key_public)
let bob_kyber_pre_key_signature = bob_identity_key.privateKey.generateSignature(message: bob_kyber_pre_key_public)
let prekey_id: UInt32 = 4570
let signed_prekey_id: UInt32 = 3006
let kyber_prekey_id: UInt32 = 7777
let bob_bundle = try PreKeyBundle(
registrationId: bob_store.localRegistrationId(context: NullContext()),
deviceId: 9,
prekeyId: prekey_id,
prekey: bob_pre_key.publicKey,
signedPrekeyId: signed_prekey_id,
signedPrekey: bob_signed_pre_key.publicKey,
signedPrekeySignature: bob_signed_pre_key_signature,
identity: bob_identity_key.identityKey,
kyberPrekeyId: kyber_prekey_id,
kyberPrekey: bob_kyber_pre_key.publicKey,
kyberPrekeySignature: bob_kyber_pre_key_signature,
)
// Alice processes the bundle:
try processPreKeyBundle(
bob_bundle,
for: bob_address,
sessionStore: alice_store,
identityStore: alice_store,
now: Date(timeIntervalSinceReferenceDate: 0),
context: NullContext(),
usePqRatchet: true
)
// If these assertions fail, it likely means that
// MAX_UNACKNOWLEDGED_SESSION_AGE has been changed. If the value has been
// decreased, we should decrease maxUnacknowledgedSessionAge after a 90-day
// rollout. If the value has been increased, we should have increased
// maxUnacknowledgedSessionAge 90 days ago.
let initial_session = try alice_store.loadSession(for: bob_address, context: NullContext())!
XCTAssertTrue(initial_session.hasCurrentState(now: Date(timeIntervalSinceReferenceDate: PreKeyManagerImpl.Constants.maxUnacknowledgedSessionAge)))
XCTAssertFalse(initial_session.hasCurrentState(now: Date(timeIntervalSinceReferenceDate: PreKeyManagerImpl.Constants.maxUnacknowledgedSessionAge + 1)))
}
}