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