2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #import <Foundation/Foundation.h>
27 #import <CloudKit/CloudKit.h>
28 #import <CloudKit/CKContainer_Private.h>
29 #import "keychain/ckks/CloudKitDependencies.h"
30 #import "keychain/ckks/CKKSCondition.h"
31 #include <Security/SecureObjectSync/SOSCloudCircle.h>
34 * Implements a 'debouncer' to store the current CK account and circle state, and receive updates to it.
36 * Will only be considered "logged in" if we both have a CK account and are 'in circle'.
38 * It will notify listeners on account state changes, so multiple repeated account state notifications with the same state are filtered by this class.
39 * Listeners can also get the 'current' state, no matter what it is. They will also then be atomically added to the notification queue, and so will
40 * always receive the next update, preventing them from getting a stale state and missing an immediate update.
43 typedef NS_ENUM(NSInteger
, CKKSAccountStatus
) {
44 /* Set at initialization. This means we haven't figured out what the account state is. */
45 CKKSAccountStatusUnknown
= 0,
46 /* We have an iCloud account and are in-circle */
47 CKKSAccountStatusAvailable
= 1,
48 /* No iCloud account is logged in on this device, or we're out of circle */
49 CKKSAccountStatusNoAccount
= 3,
52 @protocol CKKSAccountStateListener
53 -(void)ckAccountStatusChange
: (CKKSAccountStatus
)oldStatus to
:(CKKSAccountStatus
)currentStatus
;
56 @interface CKKSCKAccountStateTracker
: NSObject
57 @property CKKSCondition
* finishedInitialCalls
;
59 // If you use these, please be aware they could change out from under you at any time
60 @property CKAccountInfo
* currentCKAccountInfo
;
61 @property SOSCCStatus currentCircleStatus
;
63 // Fetched and memoized from CloudKit; we can't afford deadlocks with their callbacks
64 @
property (copy
) NSString
* ckdeviceID
;
65 @property NSError
* ckdeviceIDError
;
66 @property CKKSCondition
* ckdeviceIDInitialized
;
68 // Fetched and memoized from the Account when we're in-circle; our threading model is strange
69 @property NSString
* accountCirclePeerID
;
70 @property NSError
* accountCirclePeerIDError
;
71 @property CKKSCondition
* accountCirclePeerIDInitialized
;
73 -(instancetype
)init
: (CKContainer
*) container nsnotificationCenterClass
: (Class
<CKKSNSNotificationCenter
>) nsnotificationCenterClass
;
75 -(CKKSAccountStatus
)currentCKAccountStatusAndNotifyOnChange
: (id
<CKKSAccountStateListener
>) listener
;
77 // Methods useful for testing:
79 // Call this to simulate a notification (and pause the calling thread until all notifications are delivered)
80 -(void)notifyCKAccountStatusChangeAndWaitForSignal
;
81 -(void)notifyCircleStatusChangeAndWaitForSignal
;
83 +(SOSCCStatus
)getCircleStatus
;
84 +(void)fetchCirclePeerID
:(void (^)(NSString
* peerID
, NSError
* error
))callback
;
85 +(NSString
*)stringFromAccountStatus
: (CKKSAccountStatus
) status
;