]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSZoneStateEntry.m
Security-58286.1.32.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
28 #import "CKKSKeychainView.h"
29
30 #include <utilities/SecDb.h>
31 #include <securityd/SecDbItem.h>
32 #include <securityd/SecItemSchema.h>
33
34 #if OCTAGON
35
36 #import <CloudKit/CloudKit.h>
37 #import "CKKSZoneStateEntry.h"
38 #import "keychain/ckks/CKKSRateLimiter.h"
39
40
41 @implementation CKKSZoneStateEntry
42
43 - (instancetype) initWithCKZone: (NSString*) ckzone zoneCreated: (bool) ckzonecreated zoneSubscribed: (bool) ckzonesubscribed changeToken: (NSData*) changetoken lastFetch: (NSDate*) lastFetch encodedRateLimiter: (NSData*) encodedRateLimiter {
44 if(self = [super init]) {
45 _ckzone = ckzone;
46 _ckzonecreated = ckzonecreated;
47 _ckzonesubscribed = ckzonesubscribed;
48 _encodedChangeToken = changetoken;
49 _lastFetchTime = lastFetch;
50
51 self.encodedRateLimiter = encodedRateLimiter;
52 }
53 return self;
54 }
55
56 - (BOOL)isEqual: (id) object {
57 if(![object isKindOfClass:[CKKSZoneStateEntry class]]) {
58 return NO;
59 }
60
61 CKKSZoneStateEntry* obj = (CKKSZoneStateEntry*) object;
62
63 return ([self.ckzone isEqualToString: obj.ckzone] &&
64 self.ckzonecreated == obj.ckzonecreated &&
65 self.ckzonesubscribed == obj.ckzonesubscribed &&
66 ((self.encodedChangeToken == nil && obj.encodedChangeToken == nil) || [self.encodedChangeToken isEqual: obj.encodedChangeToken]) &&
67 ((self.lastFetchTime == nil && obj.lastFetchTime == nil) || [self.lastFetchTime isEqualToDate: obj.lastFetchTime]) &&
68 ((self.rateLimiter == nil && obj.rateLimiter == nil) || [self.rateLimiter isEqual: obj.rateLimiter])
69 ) ? YES : NO;
70 }
71
72 + (instancetype) state: (NSString*) ckzone {
73 NSError* error = nil;
74 CKKSZoneStateEntry* ret = [CKKSZoneStateEntry tryFromDatabase:ckzone error:&error];
75
76 if(error) {
77 secerror("CKKS: error fetching CKState(%@): %@", ckzone, error);
78 }
79
80 if(!ret) {
81 ret = [[CKKSZoneStateEntry alloc] initWithCKZone: ckzone zoneCreated: false zoneSubscribed: false changeToken: nil lastFetch:nil encodedRateLimiter: nil];
82 }
83 return ret;
84 }
85
86 - (CKServerChangeToken*) getChangeToken {
87 if(self.encodedChangeToken) {
88 NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:self.encodedChangeToken];
89 unarchiver.requiresSecureCoding = YES;
90 return [unarchiver decodeObjectOfClass:[CKServerChangeToken class] forKey:NSKeyedArchiveRootObjectKey];
91 } else {
92 return nil;
93 }
94 }
95
96 - (void) setChangeToken: (CKServerChangeToken*) token {
97 self.encodedChangeToken = token ? [NSKeyedArchiver archivedDataWithRootObject:token] : nil;
98 }
99
100 - (NSData*)encodedRateLimiter {
101 if(self.rateLimiter == nil) {
102 return nil;
103 }
104 return [NSKeyedArchiver archivedDataWithRootObject: self.rateLimiter];
105 }
106
107 - (void)setEncodedRateLimiter:(NSData *)encodedRateLimiter {
108 if(encodedRateLimiter == nil) {
109 self.rateLimiter = nil;
110 return;
111 }
112
113 NSKeyedUnarchiver* unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:encodedRateLimiter];
114 unarchiver.requiresSecureCoding = YES;
115 self.rateLimiter = [unarchiver decodeObjectOfClass: [CKKSRateLimiter class] forKey:NSKeyedArchiveRootObjectKey];
116 }
117
118 #pragma mark - Database Operations
119
120 + (instancetype) fromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error {
121 return [self fromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error];
122 }
123
124 + (instancetype) tryFromDatabase: (NSString*) ckzone error: (NSError * __autoreleasing *) error {
125 return [self tryFromDatabaseWhere: @{@"ckzone": CKKSNilToNSNull(ckzone)} error: error];
126 }
127
128 #pragma mark - CKKSSQLDatabaseObject methods
129
130 + (NSString*) sqlTable {
131 return @"ckstate";
132 }
133
134 + (NSArray<NSString*>*) sqlColumns {
135 return @[@"ckzone", @"ckzonecreated", @"ckzonesubscribed", @"changetoken", @"lastfetch", @"ratelimiter"];
136 }
137
138 - (NSDictionary<NSString*,NSString*>*) whereClauseToFindSelf {
139 return @{@"ckzone": self.ckzone};
140 }
141
142 - (NSDictionary<NSString*,NSString*>*) sqlValues {
143 NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init];
144
145 return @{@"ckzone": self.ckzone,
146 @"ckzonecreated": [NSNumber numberWithBool:self.ckzonecreated],
147 @"ckzonesubscribed": [NSNumber numberWithBool:self.ckzonesubscribed],
148 @"changetoken": CKKSNilToNSNull([self.encodedChangeToken base64EncodedStringWithOptions:0]),
149 @"lastfetch": CKKSNilToNSNull(self.lastFetchTime ? [dateFormat stringFromDate: self.lastFetchTime] : nil),
150 @"ratelimiter": CKKSNilToNSNull([self.encodedRateLimiter base64EncodedStringWithOptions:0])
151 };
152 }
153
154 + (instancetype) fromDatabaseRow: (NSDictionary*) row {
155 NSISO8601DateFormatter* dateFormat = [[NSISO8601DateFormatter alloc] init];
156
157 return [[CKKSZoneStateEntry alloc] initWithCKZone: row[@"ckzone"]
158 zoneCreated: [row[@"ckzonecreated"] boolValue]
159 zoneSubscribed: [row[@"ckzonesubscribed"] boolValue]
160 changeToken: ![row[@"changetoken"] isEqual: [NSNull null]] ?
161 [[NSData alloc] initWithBase64EncodedString: row[@"changetoken"] options:0] :
162 nil
163 lastFetch: [row[@"lastfetch"] isEqual: [NSNull null]] ? nil : [dateFormat dateFromString: row[@"lastfetch"]]
164 encodedRateLimiter: [row[@"ratelimiter"] isEqual: [NSNull null]] ? nil : [[NSData alloc] initWithBase64EncodedString: row[@"ratelimiter"] options:0]
165 ];
166 }
167
168 @end
169
170 #endif