]> git.saurik.com Git - apple/security.git/blob - keychain/ot/OTCloudStoreState.m
Security-59306.11.20.tar.gz
[apple/security.git] / keychain / ot / OTCloudStoreState.m
1 /*
2 * Copyright (c) 2016 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <AssertMacros.h>
25
26 #import <Foundation/Foundation.h>
27 #import <Foundation/NSKeyedArchiver_Private.h>
28
29 #import "CKKSKeychainView.h"
30
31 #include <utilities/SecDb.h>
32 #include <securityd/SecDbItem.h>
33 #include <securityd/SecItemSchema.h>
34
35 #if OCTAGON
36
37 #import <CloudKit/CloudKit.h>
38 #import "OTCloudStoreState.h"
39
40 @implementation OTCloudStoreState
41
42 - (instancetype)initWithCKZone:(NSString*)ckzone
43 zoneCreated:(bool)ckzonecreated
44 zoneSubscribed:(bool)ckzonesubscribed
45 changeToken:(NSData*)changetoken
46 lastFetch:(NSDate*)lastFetch
47 {
48 if(self = [super init]) {
49 _ckzone = [ckzone copy];
50 _ckzonecreated = ckzonecreated;
51 _ckzonesubscribed = ckzonesubscribed;
52 _encodedChangeToken = [changetoken copy];
53 _lastFetchTime = [lastFetch copy];
54 }
55 return self;
56 }
57
58 - (BOOL)isEqual: (id) object {
59 if(![object isKindOfClass:[OTCloudStoreState class]]) {
60 return NO;
61 }
62
63 OTCloudStoreState* obj = (OTCloudStoreState*) object;
64
65 return ([self.ckzone isEqualToString: obj.ckzone] &&
66 self.ckzonecreated == obj.ckzonecreated &&
67 self.ckzonesubscribed == obj.ckzonesubscribed &&
68 ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) &&
69 ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) &&
70 true) ? YES : NO;
71 }
72
73 + (instancetype) state: (NSString*) ckzone {
74 NSError* error = nil;
75 OTCloudStoreState* ret = [OTCloudStoreState tryFromDatabase:ckzone error:&error];
76
77 if(error) {
78 secerror("octagon: error fetching CKState(%@): %@", ckzone, error);
79 }
80
81 if(!ret) {
82 ret = [[OTCloudStoreState alloc] initWithCKZone:ckzone
83 zoneCreated:false
84 zoneSubscribed:false
85 changeToken:nil
86 lastFetch:nil];
87 }
88 return ret;
89 }
90
91 - (CKServerChangeToken*) getChangeToken {
92 if(self.encodedChangeToken) {
93 NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:self.encodedChangeToken error:nil];
94 return [unarchiver decodeObjectOfClass:[CKServerChangeToken class] forKey:NSKeyedArchiveRootObjectKey];
95 } else {
96 return nil;
97 }
98 }
99
100 - (void)setChangeToken: (CKServerChangeToken*) token {
101 self.encodedChangeToken = token ? [NSKeyedArchiver archivedDataWithRootObject:token requiringSecureCoding:YES error:nil] : nil;
102 }
103
104 #pragma mark - Database Operations
105
106 + (instancetype) fromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error {
107 return [self fromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error];
108 }
109
110 + (instancetype) tryFromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error {
111 return [self tryFromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error];
112 }
113
114 #pragma mark - CKKSSQLDatabaseObject methods
115
116 + (NSString*) sqlTable {
117 return @"ckstate";
118 }
119
120 + (NSArray<NSString*>*) sqlColumns {
121 return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup"];
122 }
123
124 - (NSDictionary<NSString*,NSString*>*) whereClauseToFindSelf {
125 return @{@"ckzone": self.ckzone};
126 }
127
128 - (NSDictionary<NSString*,id>*) sqlValues {
129 NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init];
130
131 return @{@"ckzone": self.ckzone,
132 @"ckzonecreated": [NSNumber numberWithBool:self.ckzonecreated],
133 @"ckzonesubscribed": [NSNumber numberWithBool:self.ckzonesubscribed],
134 @"changetoken": CKKSNilToNSNull([self.encodedChangeToken base64EncodedStringWithOptions:0]),
135 @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil),
136 };
137 }
138
139 + (instancetype)fromDatabaseRow:(NSDictionary<NSString*, CKKSSQLResult*>*)row {
140 return [[OTCloudStoreState alloc] initWithCKZone:row[@"ckzone"].asString
141 zoneCreated:row[@"ckzonecreated"].asBOOL
142 zoneSubscribed:row[@"ckzonesubscribed"].asBOOL
143 changeToken:row[@"changetoken"].asBase64DecodedData
144 lastFetch:row[@"lastfetch"].asISO8601Date
145 ];
146 }
147
148 @end
149
150 #endif //OTCloudStoreState
151