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/CKContainer_Private.h>
28 #import <CloudKit/CloudKit.h>
29 #include <Security/SecureObjectSync/SOSCloudCircle.h>
30 #import "keychain/ckks/CKKSCondition.h"
31 #import "keychain/ckks/CloudKitDependencies.h"
33 NS_ASSUME_NONNULL_BEGIN
36 * Implements a 'debouncer' to store the current CK account and circle state, and receive updates to it.
38 * Will only be considered "logged in" if we both have a CK account and are 'in circle'.
40 * It will notify listeners on account state changes, so multiple repeated account state notifications with the same state are filtered by this class.
41 * 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
42 * always receive the next update, preventing them from getting a stale state and missing an immediate update.
45 typedef NS_ENUM(NSInteger
, CKKSAccountStatus
) {
46 /* Set at initialization. This means we haven't figured out what the account state is. */
47 CKKSAccountStatusUnknown
= 0,
48 /* We have an iCloud account and are in-circle */
49 CKKSAccountStatusAvailable
= 1,
50 /* No iCloud account is logged in on this device, or we're out of circle */
51 CKKSAccountStatusNoAccount
= 3,
54 @protocol CKKSAccountStateListener
<NSObject
>
55 - (void)ckAccountStatusChange
:(CKKSAccountStatus
)oldStatus to
:(CKKSAccountStatus
)currentStatus
;
58 @interface CKKSCKAccountStateTracker
: NSObject
59 @property CKKSCondition
* finishedInitialDispatches
;
61 // If you use these, please be aware they could change out from under you at any time
62 @
property (nullable
) CKAccountInfo
* currentCKAccountInfo
;
63 @property SOSCCStatus currentCircleStatus
;
65 @
property (readonly
,atomic
) CKKSAccountStatus currentComputedAccountStatus
;
66 @
property (nullable
,readonly
,atomic
) NSError
* currentAccountError
;
67 @property CKKSCondition
* currentComputedAccountStatusValid
;
69 // Fetched and memoized from CloudKit; we can't afford deadlocks with their callbacks
70 @
property (nullable
, copy
) NSString
* ckdeviceID
;
71 @
property (nullable
) NSError
* ckdeviceIDError
;
72 @property CKKSCondition
* ckdeviceIDInitialized
;
74 // Fetched and memoized from the Account when we're in-circle; our threading model is strange
75 @
property (nullable
) NSString
* accountCirclePeerID
;
76 @
property (nullable
) NSError
* accountCirclePeerIDError
;
77 @property CKKSCondition
* accountCirclePeerIDInitialized
;
79 - (instancetype
)init
:(CKContainer
*)container nsnotificationCenterClass
:(Class
<CKKSNSNotificationCenter
>)nsnotificationCenterClass
;
81 - (dispatch_semaphore_t
)notifyOnAccountStatusChange
:(id
<CKKSAccountStateListener
>)listener
;
83 // Methods useful for testing:
85 // Call this to simulate a notification (and pause the calling thread until all notifications are delivered)
86 - (void)notifyCKAccountStatusChangeAndWaitForSignal
;
87 - (void)notifyCircleStatusChangeAndWaitForSignal
;
89 - (dispatch_group_t _Nullable
)checkForAllDeliveries
;
91 + (SOSCCStatus
)getCircleStatus
;
92 + (void)fetchCirclePeerID
:(void (^)(NSString
* _Nullable peerID
, NSError
* _Nullable error
))callback
;
93 + (NSString
*)stringFromAccountStatus
:(CKKSAccountStatus
)status
;