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 |
} |