3 class OctagonResetTests: OctagonTestsBase {
4 func testAccountAvailableAndHandleExternalCall() throws {
5 self.startCKAccountStatusMock()
7 self.cuttlefishContext.startOctagonStateMachine()
8 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
9 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
11 _ = try self.cuttlefishContext.accountAvailable("13453464")
13 self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in
14 XCTAssertNil(resetError, "should be no error resetting and establishing")
17 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
18 self.verifyDatabaseMocks()
21 func testExernalCallAndAccountAvailable() throws {
22 self.startCKAccountStatusMock()
24 self.cuttlefishContext.startOctagonStateMachine()
25 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
26 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
28 self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in
29 XCTAssertNil(resetError, "should be no error resetting and establishing")
32 _ = try self.cuttlefishContext.accountAvailable("13453464")
34 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
35 self.verifyDatabaseMocks()
38 func testCallingAccountAvailableDuringResetAndEstablish() throws {
39 self.startCKAccountStatusMock()
41 self.cuttlefishContext.startOctagonStateMachine()
42 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
43 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
45 self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in
46 XCTAssertNil(resetError, "should be no error resetting and establishing")
49 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateResetAndEstablish, within: 1 * NSEC_PER_SEC)
51 _ = try self.cuttlefishContext.accountAvailable("13453464")
53 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
54 self.verifyDatabaseMocks()
57 func testResetAndEstablishWithEscrow() throws {
58 let contextName = OTDefaultContext
59 let containerName = OTCKContainerName
61 self.startCKAccountStatusMock()
63 // Before resetAndEstablish, there shouldn't be any stored account state
64 XCTAssertThrowsError(try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName), "Before doing anything, loading a non-existent account state should fail")
66 let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs")
67 let escrowRequestNotification = expectation(forNotification: OTMockEscrowRequestNotification,
70 self.manager.resetAndEstablish(containerName,
72 altDSID: "new altDSID",
73 resetReason: .testGenerated) { resetError in
74 XCTAssertNil(resetError, "Should be no error calling resetAndEstablish")
75 resetAndEstablishExpectation.fulfill()
78 self.wait(for: [resetAndEstablishExpectation], timeout: 10)
79 self.wait(for: [escrowRequestNotification], timeout: 5)
80 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
82 let selfPeerID = try self.cuttlefishContext.accountMetadataStore.loadOrCreateAccountMetadata().peerID
84 // After resetAndEstablish, you should be able to see the persisted account state
86 let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName)
87 XCTAssertEqual(selfPeerID, accountState.peerID, "Saved account state should have the same peer ID that prepare returned")
89 XCTFail("error loading account state: \(error)")
93 func testResetAndEstablishStopsCKKS() throws {
94 let contextName = OTDefaultContext
95 let containerName = OTCKContainerName
97 self.startCKAccountStatusMock()
99 self.cuttlefishContext.startOctagonStateMachine()
100 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
101 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
104 let clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated)
105 XCTAssertNotNil(clique, "Clique should not be nil")
107 XCTFail("Shouldn't have errored making new friends: \(error)")
110 // Now, we should be in 'ready'
111 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
112 self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
113 self.assertConsidersSelfTrustedCachedAccountStatus(context: self.cuttlefishContext)
115 // and all subCKKSes should enter ready...
116 assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
117 self.verifyDatabaseMocks()
119 // CKKS should pass through "waitfortrust" during a reset
120 let waitfortrusts = self.ckksViews.compactMap { view in
121 (view as! CKKSKeychainView).keyHierarchyConditions[SecCKKSZoneKeyStateWaitForTrust] as? CKKSCondition
123 XCTAssert(!waitfortrusts.isEmpty, "Should have at least one waitfortrust condition")
125 let resetAndEstablishExpectation = self.expectation(description: "resetAndEstablish callback occurs")
126 let escrowRequestNotification = expectation(forNotification: OTMockEscrowRequestNotification,
129 self.manager.resetAndEstablish(containerName,
130 context: contextName,
131 altDSID: "new altDSID",
132 resetReason: .testGenerated) { resetError in
133 XCTAssertNil(resetError, "Should be no error calling resetAndEstablish")
134 resetAndEstablishExpectation.fulfill()
137 self.wait(for: [resetAndEstablishExpectation], timeout: 10)
138 self.wait(for: [escrowRequestNotification], timeout: 5)
139 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
141 assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
143 // CKKS should have all gone into waitfortrust during that time
144 for condition in waitfortrusts {
145 XCTAssertEqual(0, condition.wait(10 * NSEC_PER_MSEC), "CKKS should have entered waitfortrust")
149 func testOctagonResetAlsoResetsCKKSViewsMissingTLKs() {
150 self.putFakeKeyHierarchiesInCloudKit()
152 let zoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
153 XCTAssertNotNil(zoneKeys, "Should have some zone keys")
154 XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set")
156 self.startCKAccountStatusMock()
157 self.cuttlefishContext.startOctagonStateMachine()
158 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
159 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
160 assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTrust, within: 10 * NSEC_PER_SEC)
162 self.silentZoneDeletesAllowed = true
165 _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated)
167 XCTFail("failed to make new friends: \(error)")
170 assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
172 let laterZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
173 XCTAssertNotNil(laterZoneKeys, "Should have some zone keys")
174 XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset")
175 XCTAssertNotEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have different keys")
178 func testOctagonResetIgnoresOldRemoteDevicesWithKeysAndResetsCKKS() {
179 // CKKS has no keys, and there's another device claiming to have them already, but it's old
180 self.putFakeKeyHierarchiesInCloudKit()
181 self.putFakeDeviceStatusesInCloudKit()
184 (self.zones![self.manateeZoneID!]! as! FakeCKZone).currentDatabase.allValues.forEach { record in
185 let r = record as! CKRecord
186 if r.recordType == SecCKRecordDeviceStateType {
187 r.creationDate = NSDate.distantPast
188 r.modificationDate = NSDate.distantPast
192 (self.zones![self.limitedPeersAllowedZoneID!]! as! FakeCKZone).currentDatabase.allValues.forEach { record in
193 let r = record as! CKRecord
194 if r.recordType == SecCKRecordDeviceStateType {
195 r.creationDate = NSDate.distantPast
196 r.modificationDate = NSDate.distantPast
201 let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
202 XCTAssertNotNil(zoneKeys, "Should have some zone keys for Manatee")
203 XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set for Manatee")
206 let lpZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
207 XCTAssertNotNil(lpZoneKeys, "Should have some zone keys for LimitedPeers")
208 XCTAssertNotNil(lpZoneKeys?.tlk, "Should have a tlk in the original key set for LimitedPeers")
210 self.startCKAccountStatusMock()
211 self.cuttlefishContext.startOctagonStateMachine()
212 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
213 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
215 self.silentZoneDeletesAllowed = true
218 _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated)
220 XCTFail("failed to make new friends: \(error)")
223 self.assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
226 let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
227 XCTAssertNotNil(laterZoneKeys, "Should have some zone keys for Manatee")
228 XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset for Manatee")
229 XCTAssertNotEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have different keys for Manatee")
231 let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
232 XCTAssertNil(laterZoneKeys, "Should have no Manatee zone keys for aTV")
235 let laterLpZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
236 XCTAssertNotNil(laterLpZoneKeys, "Should have some zone keys for LimitedPeers")
237 XCTAssertNotNil(laterLpZoneKeys?.tlk, "Should have a tlk in the newly created keyset for LimitedPeers")
238 XCTAssertNotEqual(lpZoneKeys?.tlk?.uuid, laterLpZoneKeys?.tlk?.uuid, "CKKS zone should now have different keys for LimitedPeers")
241 func testOctagonResetWithRemoteDevicesWithKeysDoesNotResetCKKS() {
242 // CKKS has no keys, and there's another device claiming to have them already, so CKKS won't immediately reset it
243 self.putFakeKeyHierarchiesInCloudKit()
244 self.putFakeDeviceStatusesInCloudKit()
247 let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
248 XCTAssertNotNil(zoneKeys, "Should have some zone keys")
249 XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set")
252 let lpZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
253 XCTAssertNotNil(lpZoneKeys, "Should have some zone keys for LimitedPeers")
254 XCTAssertNotNil(lpZoneKeys?.tlk, "Should have a tlk in the original key set for LimitedPeers")
256 self.startCKAccountStatusMock()
257 self.cuttlefishContext.startOctagonStateMachine()
258 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
259 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
261 self.silentZoneDeletesAllowed = true
264 _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated)
266 XCTFail("failed to make new friends: \(error)")
269 assertAllCKKSViews(enter: SecCKKSZoneKeyStateWaitForTLK, within: 10 * NSEC_PER_SEC)
272 let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
273 XCTAssertNotNil(laterZoneKeys, "Should have some zone keys")
274 XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset")
275 XCTAssertEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys")
277 let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
278 XCTAssertNil(laterZoneKeys, "Should have no Manatee zone keys for aTV")
281 let lpLaterZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
282 XCTAssertNotNil(lpLaterZoneKeys, "Should have some zone keys for LimitedPeersAllowed")
283 XCTAssertNotNil(lpLaterZoneKeys?.tlk, "Should have a tlk in the newly created keyset for LimitedPeersAllowed")
284 XCTAssertEqual(lpZoneKeys?.tlk?.uuid, lpLaterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys for LimitedPeersAllowed")
287 func testOctagonResetWithTLKsDoesNotResetCKKS() {
288 // CKKS has the keys keys
289 self.putFakeKeyHierarchiesInCloudKit()
290 self.saveTLKMaterialToKeychain()
293 let zoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
294 XCTAssertNotNil(zoneKeys, "Should have some zone keys")
295 XCTAssertNotNil(zoneKeys?.tlk, "Should have a tlk in the original key set")
298 let lpZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
299 XCTAssertNotNil(lpZoneKeys, "Should have some zone keys for LimitedPeers")
300 XCTAssertNotNil(lpZoneKeys?.tlk, "Should have a tlk in the original key set for LimitedPeers")
302 self.startCKAccountStatusMock()
303 self.cuttlefishContext.startOctagonStateMachine()
304 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
305 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
308 _ = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated)
310 XCTFail("failed to make new friends: \(error)")
312 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
314 assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
317 let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
318 XCTAssertNotNil(laterZoneKeys, "Should have some zone keys")
319 XCTAssertNotNil(laterZoneKeys?.tlk, "Should have a tlk in the newly created keyset")
320 XCTAssertEqual(zoneKeys?.tlk?.uuid, laterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys")
322 let laterZoneKeys = self.keys![self.manateeZoneID!] as? ZoneKeys
323 XCTAssertNil(laterZoneKeys, "Should have no Manatee zone keys for aTV")
326 let lpLaterZoneKeys = self.keys![self.limitedPeersAllowedZoneID!] as? ZoneKeys
327 XCTAssertNotNil(lpLaterZoneKeys, "Should have some zone keys for LimitedPeersAllowed")
328 XCTAssertNotNil(lpLaterZoneKeys?.tlk, "Should have a tlk in the newly created keyset for LimitedPeersAllowed")
329 XCTAssertEqual(lpZoneKeys?.tlk?.uuid, lpLaterZoneKeys?.tlk?.uuid, "CKKS zone should now have the same keys for LimitedPeersAllowed")
332 func testOctagonResetAndEstablishFail() throws {
333 // Make sure if establish fail we end up in untrusted instead of error
334 self.startCKAccountStatusMock()
336 self.cuttlefishContext.startOctagonStateMachine()
337 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
338 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
340 _ = try self.cuttlefishContext.accountAvailable("13453464")
342 let establishExpectation = self.expectation(description: "establishExpectation")
343 let resetExpectation = self.expectation(description: "resetExpectation")
345 self.fakeCuttlefishServer.establishListener = { [unowned self] request in
346 self.fakeCuttlefishServer.establishListener = nil
347 establishExpectation.fulfill()
349 return FakeCuttlefishServer.makeCloudKitCuttlefishError(code: .establishFailed)
352 self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in
353 resetExpectation.fulfill()
354 XCTAssertNotNil(resetError, "should error resetting and establishing")
356 self.wait(for: [establishExpectation, resetExpectation], timeout: 10)
358 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
359 self.verifyDatabaseMocks()
362 func testResetReasonUnknown() throws {
363 self.startCKAccountStatusMock()
365 self.cuttlefishContext.startOctagonStateMachine()
366 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
367 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
369 _ = try self.cuttlefishContext.accountAvailable("13453464")
371 let resetExpectation = self.expectation(description: "resetExpectation")
373 self.fakeCuttlefishServer.resetListener = { request in
374 self.fakeCuttlefishServer.resetListener = nil
375 resetExpectation.fulfill()
376 XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.unknown.rawValue, "reset reason should be unknown")
380 let establishAndResetExpectation = self.expectation(description: "resetExpectation")
381 self.cuttlefishContext.rpcResetAndEstablish(.unknown) { resetError in
382 establishAndResetExpectation.fulfill()
383 XCTAssertNil(resetError, "should not error resetting and establishing")
385 self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10)
387 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
388 self.verifyDatabaseMocks()
391 func testResetReasonUserInitiatedReset() throws {
392 // Make sure if establish fail we end up in untrusted instead of error
393 self.startCKAccountStatusMock()
395 self.cuttlefishContext.startOctagonStateMachine()
396 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
397 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
399 _ = try self.cuttlefishContext.accountAvailable("13453464")
401 let resetExpectation = self.expectation(description: "resetExpectation")
403 self.fakeCuttlefishServer.resetListener = { request in
404 self.fakeCuttlefishServer.resetListener = nil
405 resetExpectation.fulfill()
406 XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.userInitiatedReset.rawValue, "reset reason should be user initiated reset")
410 let establishAndResetExpectation = self.expectation(description: "resetExpectation")
412 let recoverykeyotcliqueContext = OTConfigurationContext()
413 recoverykeyotcliqueContext.context = OTDefaultContext
414 recoverykeyotcliqueContext.dsid = "13453464"
415 recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID!
416 recoverykeyotcliqueContext.otControl = self.otControl
418 clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .userInitiatedReset)
419 XCTAssertNotNil(clique, "Clique should not be nil")
420 XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call")
421 establishAndResetExpectation.fulfill()
423 XCTFail("Shouldn't have errored making new friends: \(error)")
426 self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10)
428 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
429 self.verifyDatabaseMocks()
432 func testResetReasonRecoveryKey() throws {
433 // Make sure if establish fail we end up in untrusted instead of error
434 self.startCKAccountStatusMock()
436 self.cuttlefishContext.startOctagonStateMachine()
437 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
438 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
440 _ = try self.cuttlefishContext.accountAvailable("13453464")
442 let resetExpectation = self.expectation(description: "resetExpectation")
444 self.fakeCuttlefishServer.resetListener = { request in
445 self.fakeCuttlefishServer.resetListener = nil
446 resetExpectation.fulfill()
447 XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.recoveryKey.rawValue, "reset reason should be recovery key")
451 let recoveryKey = SecPasswordGenerate(SecPasswordType(kSecPasswordTypeiCloudRecoveryKey), nil, nil)! as String
452 XCTAssertNotNil(recoveryKey, "recoveryKey should not be nil")
454 let newCliqueContext = OTConfigurationContext()
455 newCliqueContext.context = OTDefaultContext
456 newCliqueContext.dsid = self.otcliqueContext.dsid
457 newCliqueContext.altDSID = self.mockAuthKit.altDSID!
458 newCliqueContext.otControl = self.otControl
460 let joinWithRecoveryKeyExpectation = self.expectation(description: "joinWithRecoveryKeyExpectation callback occurs")
461 TestsObjectiveC.recoverOctagon(usingData: newCliqueContext, recoveryKey: recoveryKey) { error in
462 XCTAssertNil(error, "error should be nil")
463 joinWithRecoveryKeyExpectation.fulfill()
465 self.wait(for: [joinWithRecoveryKeyExpectation], timeout: 10)
466 self.wait(for: [resetExpectation], timeout: 10)
468 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
469 self.verifyDatabaseMocks()
472 func testResetReasonNoValidBottle() throws {
473 self.startCKAccountStatusMock()
475 self.cuttlefishContext.startOctagonStateMachine()
476 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
477 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
479 let initiatorContext = self.manager.context(forContainerName: OTCKContainerName,
480 contextID: "restoreContext",
481 sosAdapter: OTSOSMissingAdapter(),
482 authKitAdapter: self.mockAuthKit2,
483 lockStateTracker: self.lockStateTracker,
484 accountStateTracker: self.accountStateTracker,
485 deviceInformationAdapter: self.makeInitiatorDeviceInfoAdapter())
487 initiatorContext.startOctagonStateMachine()
488 let newOTCliqueContext = OTConfigurationContext()
489 newOTCliqueContext.context = OTDefaultContext
490 newOTCliqueContext.dsid = self.otcliqueContext.dsid
491 newOTCliqueContext.altDSID = self.otcliqueContext.altDSID
492 newOTCliqueContext.otControl = self.otcliqueContext.otControl
493 newOTCliqueContext.sbd = OTMockSecureBackup(bottleID: nil, entropy: nil)
495 let resetExpectation = self.expectation(description: "resetExpectation callback occurs")
496 self.fakeCuttlefishServer.resetListener = { request in
497 self.fakeCuttlefishServer.resetListener = nil
498 resetExpectation.fulfill()
499 XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.noBottleDuringEscrowRecovery.rawValue, "reset reason should be no bottle during escrow recovery")
503 let newClique: OTClique
505 newClique = try OTClique.performEscrowRecovery(withContextData: newOTCliqueContext, escrowArguments: [:])
506 XCTAssertNotNil(newClique, "newClique should not be nil")
508 XCTFail("Shouldn't have errored recovering: \(error)")
511 self.wait(for: [resetExpectation], timeout: 10)
515 func testResetReasonHealthCheck() throws {
517 let containerName = OTCKContainerName
518 let contextName = OTDefaultContext
520 self.cuttlefishContext.startOctagonStateMachine()
521 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
522 self.startCKAccountStatusMock()
524 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
528 clique = try OTClique.newFriends(withContextData: self.otcliqueContext, resetReason: .testGenerated)
529 XCTAssertNotNil(clique, "Clique should not be nil")
530 XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call")
532 XCTFail("Shouldn't have errored making new friends: \(error)")
536 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
537 self.assertConsidersSelfTrusted(context: self.cuttlefishContext)
540 let accountState = try OTAccountMetadataClassC.loadFromKeychain(forContainer: containerName, contextID: contextName)
541 XCTAssertEqual(2, accountState.trustState.rawValue, "saved account should be trusted")
543 XCTFail("error loading account state: \(error)")
546 // Reset any CFUs we've done so far
547 self.otFollowUpController.postedFollowUp = false
549 let resetExpectation = self.expectation(description: "resetExpectation callback occurs")
550 self.fakeCuttlefishServer.resetListener = { request in
551 self.fakeCuttlefishServer.resetListener = nil
552 resetExpectation.fulfill()
553 XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.healthCheck.rawValue, "reset reason should be health check")
556 self.fakeCuttlefishServer.returnResetOctagonResponse = true
557 self.aksLockState = false
558 self.lockStateTracker.recheck()
560 let healthCheckCallback = self.expectation(description: "healthCheckCallback callback occurs")
561 self.manager.healthCheck(containerName, context: contextName, skipRateLimitingCheck: false) { error in
562 XCTAssertNil(error, "error should be nil")
563 healthCheckCallback.fulfill()
565 self.wait(for: [healthCheckCallback, resetExpectation], timeout: 10)
567 assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
568 self.verifyDatabaseMocks()
570 let dumpCallback = self.expectation(description: "dumpCallback callback occurs")
571 self.tphClient.dump(withContainer: containerName, context: contextName) { dump, _ in
572 XCTAssertNotNil(dump, "dump should not be nil")
573 let egoSelf = dump!["self"] as? [String: AnyObject]
574 XCTAssertNotNil(egoSelf, "egoSelf should not be nil")
575 dumpCallback.fulfill()
577 self.wait(for: [dumpCallback], timeout: 10)
579 self.verifyDatabaseMocks()
580 self.assertEnters(context: cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
583 func testLegacyJoinCircleDoesNotReset() throws {
584 self.cuttlefishContext.startOctagonStateMachine()
585 self.startCKAccountStatusMock()
586 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
588 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
590 let establishAndResetExpectation = self.expectation(description: "resetExpectation")
592 let recoverykeyotcliqueContext = OTConfigurationContext()
593 recoverykeyotcliqueContext.context = OTDefaultContext
594 recoverykeyotcliqueContext.dsid = "13453464"
595 recoverykeyotcliqueContext.altDSID = self.mockAuthKit.altDSID!
596 recoverykeyotcliqueContext.otControl = self.otControl
598 clique = try OTClique.newFriends(withContextData: recoverykeyotcliqueContext, resetReason: .testGenerated)
599 XCTAssertNotNil(clique, "Clique should not be nil")
600 XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call")
601 establishAndResetExpectation.fulfill()
603 XCTFail("Shouldn't have errored making new friends: \(error)")
606 self.wait(for: [establishAndResetExpectation], timeout: 10)
608 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
609 self.verifyDatabaseMocks()
611 self.fakeCuttlefishServer.resetListener = { request in
612 XCTFail("requestToJoinCircle should not reset Octagon")
617 _ = try clique.requestToJoinCircle()
619 XCTFail("Shouldn't have errored requesting to join circle: \(error)")
623 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
626 func testResetReasonTestGenerated() throws {
627 self.startCKAccountStatusMock()
629 self.cuttlefishContext.startOctagonStateMachine()
630 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
631 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
633 _ = try self.cuttlefishContext.accountAvailable("13453464")
635 let resetExpectation = self.expectation(description: "resetExpectation")
637 self.fakeCuttlefishServer.resetListener = { request in
638 self.fakeCuttlefishServer.resetListener = nil
639 resetExpectation.fulfill()
640 XCTAssertTrue(request.resetReason.rawValue == CuttlefishResetReason.testGenerated.rawValue, "reset reason should be test generated")
644 let establishAndResetExpectation = self.expectation(description: "resetExpectation")
645 self.cuttlefishContext.rpcResetAndEstablish(.testGenerated) { resetError in
646 establishAndResetExpectation.fulfill()
647 XCTAssertNil(resetError, "should not error resetting and establishing")
649 self.wait(for: [establishAndResetExpectation, resetExpectation], timeout: 10)
651 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
652 self.verifyDatabaseMocks()
655 func testCliqueResetAllSPI() throws {
656 self.cuttlefishContext.startOctagonStateMachine()
657 self.startCKAccountStatusMock()
658 OctagonSetSOSFeatureEnabled(false)
660 XCTAssertNoThrow(try self.cuttlefishContext.setCDPEnabled())
662 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateUntrusted, within: 10 * NSEC_PER_SEC)
664 let establishAndResetExpectation = self.expectation(description: "resetExpectation")
666 let otcliqueContext = OTConfigurationContext()
667 var firstCliqueIdentifier: String?
669 otcliqueContext.context = OTDefaultContext
670 otcliqueContext.dsid = "13453464"
671 otcliqueContext.altDSID = self.mockAuthKit.altDSID!
672 otcliqueContext.authenticationAppleID = "appleID"
673 otcliqueContext.passwordEquivalentToken = "petpetpetpetpet"
674 otcliqueContext.otControl = self.otControl
675 otcliqueContext.ckksControl = self.ckksControl
676 otcliqueContext.sbd = OTMockSecureBackup(bottleID: nil, entropy: nil)
679 clique = try OTClique.newFriends(withContextData: otcliqueContext, resetReason: .testGenerated)
680 XCTAssertNotNil(clique, "Clique should not be nil")
681 XCTAssertNotNil(clique.cliqueMemberIdentifier, "Should have a member identifier after a clique newFriends call")
682 firstCliqueIdentifier = clique.cliqueMemberIdentifier
683 establishAndResetExpectation.fulfill()
685 XCTFail("Shouldn't have errored making new friends everything: \(error)")
688 self.wait(for: [establishAndResetExpectation], timeout: 10)
690 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
691 assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
692 self.verifyDatabaseMocks()
694 self.silentZoneDeletesAllowed = true
696 let newClique: OTClique
698 newClique = try OTClique.resetProtectedData(otcliqueContext)
699 XCTAssertNotEqual(newClique.cliqueMemberIdentifier, firstCliqueIdentifier, "clique identifiers should be different")
701 XCTFail("Shouldn't have errored resetting everything: \(error)")
704 XCTAssertNotNil(newClique, "newClique should not be nil")
706 self.assertEnters(context: self.cuttlefishContext, state: OctagonStateReady, within: 10 * NSEC_PER_SEC)
707 assertAllCKKSViews(enter: SecCKKSZoneKeyStateReady, within: 10 * NSEC_PER_SEC)
708 self.verifyDatabaseMocks()