119 lines
5.1 KiB
Swift
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)))
|
|
}
|
|
}
|