]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSZoneStateEntry.m
Security-59754.80.3.tar.gz
[apple/security.git] / keychain / ckks / CKKSZoneStateEntry.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 "keychain/securityd/SecDbItem.h"
33 #include "keychain/securityd/SecItemSchema.h"
34
35 #if OCTAGON
36
37 #import <CloudKit/CloudKit.h>
38 #import "CKKSZoneStateEntry.h"
39 #import "keychain/ckks/CKKSRateLimiter.h"
40 #import "keychain/ckks/CKKSFixups.h"
41
42
43 @implementation CKKSZoneStateEntry
44
45 - (instancetype)initWithCKZone:(NSString*)ckzone
46 zoneCreated:(bool)ckzonecreated
47 zoneSubscribed:(bool)ckzonesubscribed
48 changeToken:(NSData*)changetoken
49 moreRecordsInCloudKit:(BOOL)moreRecords
50 lastFetch:(NSDate*)lastFetch
51 lastScan:(NSDate* _Nullable)lastScan
52 lastFixup:(CKKSFixup)lastFixup
53 encodedRateLimiter:(NSData*)encodedRateLimiter
54 {
55 if(self = [super init]) {
56 _ckzone = ckzone;
57 _ckzonecreated = ckzonecreated;
58 _ckzonesubscribed = ckzonesubscribed;
59 _encodedChangeToken = changetoken;
60 _moreRecordsInCloudKit = moreRecords;
61 _lastFetchTime = lastFetch;
62 _lastLocalKeychainScanTime = lastScan;
63 _lastFixup = lastFixup;
64
65 self.encodedRateLimiter = encodedRateLimiter;
66 }
67 return self;
68 }
69
70 - (BOOL)isEqual: (id) object {
71 if(![object isKindOfClass:[CKKSZoneStateEntry class]]) {
72 return NO;
73 }
74
75 CKKSZoneStateEntry* obj = (CKKSZoneStateEntry*) object;
76
77 return ([self.ckzone isEqualToString: obj.ckzone] &&
78 self.ckzonecreated == obj.ckzonecreated &&
79 self.ckzonesubscribed == obj.ckzonesubscribed &&
80 ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) &&
81 self.moreRecordsInCloudKit == obj.moreRecordsInCloudKit &&
82 ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) &&
83 ((self.rateLimiter == nil && obj.rateLimiter == nil) || [self.rateLimiter isEqual: obj.rateLimiter]) &&
84 self.lastFixup == obj.lastFixup &&
85 ((self.lastLocalKeychainScanTime == nil && obj.lastLocalKeychainScanTime == nil) || [self.lastLocalKeychainScanTime isEqualToDate: obj.lastLocalKeychainScanTime]) &&
86 true) ? YES : NO;
87 }
88
89 + (instancetype) state: (NSString*) ckzone {
90 NSError* error = nil;
91 CKKSZoneStateEntry* ret = [CKKSZoneStateEntry tryFromDatabase:ckzone error:&error];
92
93 if(error) {
94 ckkserror_global("ckks", "error fetching CKState(%@): %@", ckzone, error);
95 }
96
97 if(!ret) {
98 ret = [[CKKSZoneStateEntry alloc] initWithCKZone:ckzone
99 zoneCreated:false
100 zoneSubscribed:false
101 changeToken:nil
102 moreRecordsInCloudKit:NO
103 lastFetch:nil
104 lastScan:nil
105 lastFixup:CKKSCurrentFixupNumber
106 encodedRateLimiter:nil];
107 }
108 return ret;
109 }
110
111 - (CKServerChangeToken* _Nullable) getChangeToken {
112 if(self.encodedChangeToken) {
113 NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:self.encodedChangeToken error:nil];
114 return [unarchiver decodeObjectOfClass:[CKServerChangeToken class] forKey:NSKeyedArchiveRootObjectKey];
115 } else {
116 return nil;
117 }
118 }
119
120 - (void) setChangeToken: (CKServerChangeToken*) token {
121 self.encodedChangeToken = token ? [NSKeyedArchiver archivedDataWithRootObject:token requiringSecureCoding:YES error:nil] : nil;
122 }
123
124 - (NSData*)encodedRateLimiter {
125 if(self.rateLimiter == nil) {
126 return nil;
127 }
128 return [NSKeyedArchiver archivedDataWithRootObject:self.rateLimiter requiringSecureCoding:YES error:nil];
129 }
130
131 - (void)setEncodedRateLimiter:(NSData *)encodedRateLimiter {
132 if(encodedRateLimiter == nil) {
133 self.rateLimiter = nil;
134 return;
135 }
136
137 NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:encodedRateLimiter error:nil];
138 self.rateLimiter = [unarchiver decodeObjectOfClass: [CKKSRateLimiter class] forKey:NSKeyedArchiveRootObjectKey];
139 }
140
141 #pragma mark - Database Operations
142
143 + (instancetype) fromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error {
144 return [self fromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error];
145 }
146
147 + (instancetype) tryFromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error {
148 return [self tryFromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error];
149 }
150
151 #pragma mark - CKKSSQLDatabaseObject methods
152
153 + (NSString*) sqlTable {
154 return @"ckstate";
155 }
156
157 + (NSArray<NSString*>*) sqlColumns {
158 // Note that 'extra' is not currently used, but the schema supports adding a protobuf or other serialized data
159 return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter", @"lastFixup", @"morecoming", @"lastscan", @"extra"];
160 }
161
162 - (NSDictionary<NSString*,NSString*>*) whereClauseToFindSelf {
163 return @{@"ckzone": self.ckzone};
164 }
165
166 - (NSDictionary<NSString*,id>*) sqlValues {
167 NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init];
168
169 return @{
170 @"ckzone": self.ckzone,
171 @"ckzonecreated": [NSNumber numberWithBool:self.ckzonecreated],
172 @"ckzonesubscribed": [NSNumber numberWithBool:self.ckzonesubscribed],
173 @"changetoken": CKKSNilToNSNull([self.encodedChangeToken base64EncodedStringWithOptions:0]),
174 @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil),
175 @"ratelimiter": CKKSNilToNSNull([self.encodedRateLimiter base64EncodedStringWithOptions:0]),
176 @"lastFixup": [NSNumber numberWithLong:self.lastFixup],
177 @"morecoming": [NSNumber numberWithBool:self.moreRecordsInCloudKit],
178 @"lastscan": CKKSNilToNSNull(self.lastLocalKeychainScanTime ? [dateFormat stringFromDate:self.lastLocalKeychainScanTime] : nil),
179 };
180 }
181
182 + (instancetype)fromDatabaseRow:(NSDictionary<NSString*, CKKSSQLResult*>*)row {
183 return [[CKKSZoneStateEntry alloc] initWithCKZone:row[@"ckzone"].asString
184 zoneCreated:row[@"ckzonecreated"].asBOOL
185 zoneSubscribed:row[@"ckzonesubscribed"].asBOOL
186 changeToken:row[@"changetoken"].asBase64DecodedData
187 moreRecordsInCloudKit:row[@"morecoming"].asBOOL
188 lastFetch:row[@"lastfetch"].asISO8601Date
189 lastScan:row[@"lastscan"].asISO8601Date
190 lastFixup:(CKKSFixup)row[@"lastFixup"].asNSInteger
191 encodedRateLimiter:row[@"ratelimiter"].asBase64DecodedData
192 ];
193 }
194
195 @end
196
197 #endif