chatsecureios / ChatSecureTests / OTROmemoStorageTest.swift @ db493e51
History | View | Annotate | Download (11.4 KB)
| 1 |
// |
|---|---|
| 2 |
// OTROMEMOStorageTest.swift |
| 3 |
// ChatSecure |
| 4 |
// |
| 5 |
// Created by David Chiles on 9/16/16. |
| 6 |
// Copyright © 2016 Chris Ballinger. All rights reserved. |
| 7 |
// |
| 8 |
|
| 9 |
import XCTest |
| 10 |
@testable import ChatSecureCore |
| 11 |
|
| 12 |
extension OTROMEMOSignalCoordinator {
|
| 13 |
convenience init(accountYapKey: String, databaseConnection: YapDatabaseConnection) throws {
|
| 14 |
let capsStorage = XMPPCapabilitiesCoreDataStorage(inMemoryStore: ())! |
| 15 |
let serverCaps = OTRServerCapabilities() |
| 16 |
let caps = XMPPCapabilities(capabilitiesStorage: capsStorage) |
| 17 |
let file = FileTransferManager(connection: databaseConnection, serverCapabilities: serverCaps, sessionConfiguration: URLSessionConfiguration.ephemeral) |
| 18 |
let messageStorage = MessageStorage(connection: databaseConnection, capabilities: caps, fileTransfer: file) |
| 19 |
try self.init(accountYapKey: accountYapKey, databaseConnection: databaseConnection, messageStorage: messageStorage) |
| 20 |
} |
| 21 |
} |
| 22 |
|
| 23 |
class OTROmemoStorageTest: XCTestCase {
|
| 24 |
|
| 25 |
var databaseManager:OTRDatabaseManager! |
| 26 |
var omemoStorage:OTROMEMOStorageManager! |
| 27 |
var signalStorage:OTRSignalStorageManager! |
| 28 |
var signalCoordinator:OTROMEMOSignalCoordinator! |
| 29 |
var accountKey:String! |
| 30 |
var accountCollection:String! |
| 31 |
let initialDevices:[NSNumber] = [1,2,3] |
| 32 |
let secondDeviceNumbers:[NSNumber] = [1,2,4,5] |
| 33 |
|
| 34 |
override func setUp() {
|
| 35 |
super.setUp() |
| 36 |
|
| 37 |
FileManager.default.clearDirectory(OTRTestDatabaseManager.yapDatabaseDirectory()) |
| 38 |
} |
| 39 |
|
| 40 |
override func tearDown() {
|
| 41 |
// Put teardown code here. This method is called after the invocation of each test method in the class. |
| 42 |
super.tearDown() |
| 43 |
} |
| 44 |
|
| 45 |
/** |
| 46 |
* This creates teh necessary database and signal managers. Also creates an account which is required for all the above objects |
| 47 |
* |
| 48 |
*/ |
| 49 |
func setupDatabase(_ name:String) {
|
| 50 |
let account = TestXMPPAccount(username: "", accountType: .jabber)! |
| 51 |
self.accountKey = account.uniqueId |
| 52 |
self.accountCollection = OTRXMPPAccount.collection |
| 53 |
|
| 54 |
|
| 55 |
self.databaseManager = OTRTestDatabaseManager() |
| 56 |
self.databaseManager.setDatabasePassphrase("help", remember: false, error: nil)
|
| 57 |
self.databaseManager.setupDatabase(withName: name, withMediaStorage: false) |
| 58 |
self.omemoStorage = OTROMEMOStorageManager(accountKey: accountKey, accountCollection:accountCollection, databaseConnection: databaseManager.readWriteDatabaseConnection!) |
| 59 |
|
| 60 |
self.signalStorage = OTRSignalStorageManager(accountKey: accountKey, databaseConnection: databaseManager.readWriteDatabaseConnection!, delegate: nil) |
| 61 |
self.signalCoordinator = try! OTROMEMOSignalCoordinator(accountYapKey: accountKey, databaseConnection: databaseManager.readWriteDatabaseConnection!) |
| 62 |
|
| 63 |
databaseManager.readWriteDatabaseConnection?.readWrite( { (transaction) in
|
| 64 |
account.save(with: transaction) |
| 65 |
}) |
| 66 |
} |
| 67 |
|
| 68 |
/** |
| 69 |
* Store the inital device list. |
| 70 |
* Ensure the correct trust level is set and that it's attached to the correct account. |
| 71 |
*/ |
| 72 |
func storeInitialDevices() {
|
| 73 |
self.omemoStorage.storeOurDevices(self.initialDevices) |
| 74 |
let firstStoredDevices = omemoStorage.getDevicesForOurAccount(nil) |
| 75 |
XCTAssertEqual(firstStoredDevices.count, self.initialDevices.count) |
| 76 |
firstStoredDevices.forEach { (device) in
|
| 77 |
XCTAssert(device.trustLevel == .trustedTofu) |
| 78 |
XCTAssertEqual(device.parentKey, self.accountKey) |
| 79 |
XCTAssertEqual(device.parentCollection, self.accountCollection) |
| 80 |
} |
| 81 |
let firstStoredDeviceId = firstStoredDevices.map { (device) -> NSNumber in
|
| 82 |
return device.deviceId |
| 83 |
} |
| 84 |
XCTAssertEqual(Set(self.initialDevices), Set(firstStoredDeviceId)) |
| 85 |
} |
| 86 |
|
| 87 |
|
| 88 |
/** |
| 89 |
* Store the second device list. This should override the inital device list and remove devie 3 and add device 4 and 5. |
| 90 |
* Checks to make sure the trust level is set correctly. |
| 91 |
*/ |
| 92 |
func storeSecondDeviceList() {
|
| 93 |
//Now simulate getting a new set of devices where one was removed and two were added. |
| 94 |
|
| 95 |
omemoStorage.storeOurDevices(self.secondDeviceNumbers) |
| 96 |
let secondStoredDevices = omemoStorage.getDevicesForOurAccount(nil) |
| 97 |
XCTAssertEqual(secondStoredDevices.count, 5) |
| 98 |
secondStoredDevices.forEach { (device) in
|
| 99 |
|
| 100 |
XCTAssertEqual(device.parentKey, accountKey) |
| 101 |
XCTAssertEqual(device.parentCollection, accountCollection) |
| 102 |
switch device.deviceId {
|
| 103 |
case 3: |
| 104 |
XCTAssert(device.trustLevel == .removed) |
| 105 |
case 4: |
| 106 |
fallthrough |
| 107 |
case 5: |
| 108 |
XCTAssert(device.trustLevel == .untrustedNew) |
| 109 |
default: |
| 110 |
XCTAssert(device.trustLevel == .trustedTofu,"Device \(device.deviceId) Should be Tofu") |
| 111 |
} |
| 112 |
} |
| 113 |
let secondStoredDeviceId = secondStoredDevices.map { (device) -> NSNumber in
|
| 114 |
return device.deviceId |
| 115 |
} |
| 116 |
XCTAssertEqual(Set([1,2,3,4,5]), Set(secondStoredDeviceId)) |
| 117 |
} |
| 118 |
|
| 119 |
func testOmemoFirstDevicesStorage() {
|
| 120 |
self.setupDatabase(#function) |
| 121 |
self.storeInitialDevices() |
| 122 |
} |
| 123 |
|
| 124 |
func testOmemoSecondDeviceStorage() {
|
| 125 |
self.setupDatabase(#function) |
| 126 |
self.storeInitialDevices() |
| 127 |
self.storeSecondDeviceList() |
| 128 |
} |
| 129 |
|
| 130 |
/** |
| 131 |
* Do the above test and then remove all devices and ensure there are no devices left. |
| 132 |
*/ |
| 133 |
func testOmemoRemoveDevices() {
|
| 134 |
self.setupDatabase(#function) |
| 135 |
self.storeInitialDevices() |
| 136 |
self.storeSecondDeviceList() |
| 137 |
|
| 138 |
let thirdDeviceNumbers = [NSNumber]() |
| 139 |
omemoStorage.storeOurDevices(thirdDeviceNumbers) |
| 140 |
let thirdStoredDevices = omemoStorage.getDevicesForParentYapKey(accountKey, yapCollection: accountCollection, trusted:true) |
| 141 |
XCTAssertEqual(thirdStoredDevices.count, 0) |
| 142 |
} |
| 143 |
|
| 144 |
/** |
| 145 |
* 1. Check to make sure there are no pre-keys currently stored. |
| 146 |
* 2. Add 3 preKeys and check that the current max is correct. |
| 147 |
* 3. Delete a pre-key and check that values are correct |
| 148 |
*/ |
| 149 |
func testPreKeyStorage() {
|
| 150 |
self.setupDatabase(#function) |
| 151 |
|
| 152 |
let none = self.signalStorage.currentMaxPreKeyId() |
| 153 |
XCTAssertNil(none) |
| 154 |
|
| 155 |
//Save a few random prekeys with id. |
| 156 |
//Normally these should be sequential but shouldn't matter |
| 157 |
let keyIds:[UInt32] = [1,2,100] |
| 158 |
keyIds.forEach { (id) in
|
| 159 |
let result = self.signalStorage.storePreKey(Data(), preKeyId: id) |
| 160 |
XCTAssertTrue(result) |
| 161 |
} |
| 162 |
|
| 163 |
XCTAssertEqual(self.signalStorage.currentMaxPreKeyId(),100) |
| 164 |
|
| 165 |
// Delete a prekey. In this case it's the max id but that shouldn't matter either. |
| 166 |
XCTAssertTrue(self.signalStorage.deletePreKey(withId:100)) |
| 167 |
XCTAssertFalse(self.signalStorage.containsPreKey(withId:100)) |
| 168 |
XCTAssertFalse(self.signalStorage.containsPreKey(withId:999)) |
| 169 |
XCTAssertTrue(self.signalStorage.containsPreKey(withId:2)) |
| 170 |
|
| 171 |
let result = self.signalStorage.currentMaxPreKeyId()! |
| 172 |
XCTAssertEqual(result, 100) |
| 173 |
|
| 174 |
//Fetch all the remaining prekeys should get back 1,2 |
| 175 |
let allRemainingPrekeys = self.signalStorage.fetchAllPreKeys(false) |
| 176 |
let remainingPreKeyIds = allRemainingPrekeys.map { (prekey) -> UInt32 in
|
| 177 |
return prekey.keyId |
| 178 |
} |
| 179 |
//Check that it has the two id expected and not the one that was deleted |
| 180 |
XCTAssertTrue(remainingPreKeyIds.contains(1)) |
| 181 |
XCTAssertTrue(remainingPreKeyIds.contains(2)) |
| 182 |
XCTAssertFalse(remainingPreKeyIds.contains(100)) |
| 183 |
XCTAssertEqual(allRemainingPrekeys.count, 2) |
| 184 |
} |
| 185 |
|
| 186 |
/** |
| 187 |
* NOTES: This test is failing because the stored bundle cannot |
| 188 |
* be validated after re-fetching, so it regenerates a completely |
| 189 |
* new bundle. Why does store/fetch corrupt the bundle? |
| 190 |
* |
| 191 |
* 1. Test generating a bundle like on first launch. |
| 192 |
* 2. Remove a few pre keys. This simulates what will happen when the signal library uses up some pre keys from incoming bundle messages |
| 193 |
* 3. Fetch our own bundle again. This time it should all come from the database and the only new information is two new pre-keys to replace teh ones deleted |
| 194 |
*/ |
| 195 |
func testOurBundleStorage() {
|
| 196 |
self.setupDatabase(#function) |
| 197 |
let firstFetch = self.signalCoordinator.fetchMyBundle()! |
| 198 |
XCTAssertNotNil(firstFetch) |
| 199 |
|
| 200 |
var firstPreKeyFetch = [UInt32:Data]() |
| 201 |
firstFetch.preKeys.forEach { (preKey) in
|
| 202 |
firstPreKeyFetch.updateValue(preKey.publicKey, forKey: preKey.preKeyId) |
| 203 |
} |
| 204 |
|
| 205 |
//Remove some pre keys |
| 206 |
XCTAssertTrue(self.signalStorage.deletePreKey(withId:22)) |
| 207 |
XCTAssertTrue(self.signalStorage.deletePreKey(withId:25)) |
| 208 |
|
| 209 |
//Fetch again |
| 210 |
let secondFetch = self.signalCoordinator.fetchMyBundle()! |
| 211 |
XCTAssertNotNil(secondFetch) |
| 212 |
|
| 213 |
var secondPreKeyFetch = [UInt32:Data]() |
| 214 |
secondFetch.preKeys.forEach { (preKey) in
|
| 215 |
secondPreKeyFetch.updateValue(preKey.publicKey, forKey: preKey.preKeyId) |
| 216 |
} |
| 217 |
|
| 218 |
XCTAssertEqual(firstFetch.deviceId, secondFetch.deviceId,"Should be the same device id") |
| 219 |
XCTAssertEqual(firstFetch.identityKey, secondFetch.identityKey,"Same Identity Key") |
| 220 |
XCTAssertEqual(firstFetch.signedPreKey.signature, secondFetch.signedPreKey.signature,"Same signature") |
| 221 |
XCTAssertEqual(firstFetch.signedPreKey.preKeyId, secondFetch.signedPreKey.preKeyId,"Same prekey Id") |
| 222 |
XCTAssertEqual(firstFetch.signedPreKey.publicKey, secondFetch.signedPreKey.publicKey,"Same prekey public key") |
| 223 |
//Checking Pre Keys |
| 224 |
|
| 225 |
let firstIdArray = Array(firstPreKeyFetch.keys).sorted() |
| 226 |
let secondIdArray = Array(secondPreKeyFetch.keys).sorted() |
| 227 |
//The two deleted keys should not show up in the second key fetch |
| 228 |
XCTAssertFalse(secondIdArray.contains(22),"Should not contain this key id") |
| 229 |
XCTAssertFalse(secondIdArray.contains(25),"Should not contain this key id") |
| 230 |
// Both times it should fetch 100 keys |
| 231 |
XCTAssertEqual(firstIdArray.count, 100,"Should have fetched 100 keys") |
| 232 |
XCTAssertEqual(secondIdArray.count, 100,"Should have fetched 100 keys") |
| 233 |
XCTAssertEqual(firstIdArray.first!, 1,"Should start with id 1") |
| 234 |
XCTAssertEqual(secondIdArray.first!, 1,"Should start with id 1") |
| 235 |
XCTAssertEqual(firstIdArray.last!, 100,"Should end with id 100") |
| 236 |
XCTAssertEqual(secondIdArray.last!, 102,"Should start with id 1") |
| 237 |
|
| 238 |
//Make sure all the data is the same as previous attempt |
| 239 |
secondPreKeyFetch.forEach { (id,secondData) in
|
| 240 |
if let firstData = firstPreKeyFetch[id] {
|
| 241 |
XCTAssertEqual(firstData, secondData,"Public key information should be the same") |
| 242 |
} else {
|
| 243 |
//These should not be in the first set because they were created after we deleted two keys |
| 244 |
let excluded:Set<UInt32> = Set([101,102]) |
| 245 |
XCTAssertTrue(excluded.contains(id)) |
| 246 |
} |
| 247 |
} |
| 248 |
|
| 249 |
//Double check to make sure that the key information is there or not there depending on added and removed keys. |
| 250 |
XCTAssertNil(self.signalStorage.loadPreKey(withId:22)) |
| 251 |
XCTAssertNil(self.signalStorage.loadPreKey(withId:25)) |
| 252 |
XCTAssertNotNil(self.signalStorage.loadPreKey(withId:101)) |
| 253 |
XCTAssertNotNil(self.signalStorage.loadPreKey(withId:102)) |
| 254 |
} |
| 255 |
} |