Statistics
| Branch: | Tag: | Revision:

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
}