]> git.saurik.com Git - apple/security.git/blob - keychain/ckks/CKKSMirrorEntry.m
Security-59754.41.1.tar.gz
[apple/security.git] / keychain / ckks / CKKSMirrorEntry.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 #if OCTAGON
25
26 #include <AssertMacros.h>
27
28 #import <Foundation/Foundation.h>
29
30 #import "CKKSKeychainView.h"
31
32 #include <utilities/SecDb.h>
33 #include "keychain/securityd/SecDbItem.h"
34 #include "keychain/securityd/SecItemSchema.h"
35
36
37 #import <CloudKit/CloudKit.h>
38 #import "CKKSOutgoingQueueEntry.h"
39 #import "CKKSMirrorEntry.h"
40 #import "CKKSSIV.h"
41
42 @implementation CKKSMirrorEntry
43
44 -(instancetype)initWithCKKSItem:(CKKSItem*)item {
45 if((self = [super init])) {
46 _item = item;
47 _wasCurrent = 0;
48 }
49 return self;
50 }
51
52 -(instancetype)initWithCKRecord:(CKRecord*)record {
53 if((self = [super init])) {
54 _item = [[CKKSItem alloc] initWithCKRecord:record];
55
56 _wasCurrent = [record[SecCKRecordServerWasCurrent] unsignedLongLongValue];
57 }
58 return self;
59 }
60
61 - (NSString*)description {
62 return [NSString stringWithFormat: @"<%@(%@): %@>",
63 NSStringFromClass([self class]),
64 self.item.zoneID.zoneName,
65 self.item.uuid];
66 }
67
68 -(void)setFromCKRecord: (CKRecord*) record {
69 [self.item setFromCKRecord: record];
70 _wasCurrent = [record[SecCKRecordServerWasCurrent] unsignedLongLongValue];
71 }
72
73 - (bool)matchesCKRecord: (CKRecord*) record {
74 bool matches = [self.item matchesCKRecord: record];
75
76 if(matches) {
77
78 // Why is obj-c nullable equality so difficult?
79 if(!((record[SecCKRecordServerWasCurrent] == nil && self.wasCurrent == 0) ||
80 [record[SecCKRecordServerWasCurrent] isEqual: [NSNumber numberWithUnsignedLongLong:self.wasCurrent]])) {
81 ckksinfo_global("ckksitem", "was_current does not match");
82 matches = false;
83 }
84 }
85 return matches;
86 }
87
88 #pragma mark - Database Operations
89
90 + (instancetype) fromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
91 return [self fromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error];
92 }
93
94 + (instancetype) tryFromDatabase: (NSString*) uuid zoneID:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
95 return [self tryFromDatabaseWhere: @{@"UUID": CKKSNilToNSNull(uuid), @"ckzone":CKKSNilToNSNull(zoneID.zoneName)} error: error];
96 }
97
98 #pragma mark - Property access to underlying CKKSItem
99
100 -(NSString*)uuid {
101 return self.item.uuid;
102 }
103
104 -(void)setUuid:(NSString *)uuid {
105 self.item.uuid = uuid;
106 }
107
108 #pragma mark - CKKSSQLDatabaseObject methods
109
110 + (NSString*) sqlTable {
111 return @"ckmirror";
112 }
113
114 + (NSArray<NSString*>*)sqlColumns {
115 return [[CKKSItem sqlColumns] arrayByAddingObjectsFromArray: @[@"wascurrent"]];
116 }
117
118 - (NSDictionary<NSString*,NSString*>*) whereClauseToFindSelf {
119 return [self.item whereClauseToFindSelf];
120 }
121
122 - (NSDictionary<NSString*,NSString*>*)sqlValues {
123 NSMutableDictionary* values = [[self.item sqlValues] mutableCopy];
124 values[@"wascurrent"] = [[NSNumber numberWithUnsignedLongLong:self.wasCurrent] stringValue];
125 return values;
126 }
127
128 + (instancetype)fromDatabaseRow:(NSDictionary<NSString*, CKKSSQLResult*>*)row {
129 CKKSMirrorEntry* ckme = [[CKKSMirrorEntry alloc] initWithCKKSItem: [CKKSItem fromDatabaseRow:row]];
130
131 // This appears to be the best way to get an unsigned long long out of a string.
132 ckme.wasCurrent = [[[[NSNumberFormatter alloc] init] numberFromString:row[@"wascurrent"].asString] unsignedLongLongValue];
133 return ckme;
134 }
135
136 + (NSDictionary<NSString*,NSNumber*>*)countsByParentKey:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
137 NSMutableDictionary* results = [[NSMutableDictionary alloc] init];
138
139 [CKKSSQLDatabaseObject queryDatabaseTable: [[self class] sqlTable]
140 where: @{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)}
141 columns: @[@"parentKeyUUID", @"count(rowid)"]
142 groupBy: @[@"parentKeyUUID"]
143 orderBy:nil
144 limit: -1
145 processRow: ^(NSDictionary<NSString*, CKKSSQLResult*>* row) {
146 results[row[@"parentKeyUUID"].asString] = row[@"count(rowid)"].asNSNumberInteger;
147 }
148 error: error];
149 return results;
150 }
151
152 + (NSNumber*)counts:(CKRecordZoneID*)zoneID error: (NSError * __autoreleasing *) error {
153 __block NSNumber *result = nil;
154
155 [CKKSSQLDatabaseObject queryDatabaseTable: [[self class] sqlTable]
156 where: @{@"ckzone": CKKSNilToNSNull(zoneID.zoneName)}
157 columns: @[@"count(rowid)"]
158 groupBy:nil
159 orderBy:nil
160 limit: -1
161 processRow: ^(NSDictionary<NSString*, CKKSSQLResult*>* row) {
162 result = row[@"count(rowid)"].asNSNumberInteger;
163 }
164 error: error];
165 return result;
166
167 }
168
169
170 @end
171
172 #endif