1/*
2 * Copyright (c) 2013-2014 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 <SecureObjectSync/SOSKVSKeys.h>
25#include <utilities/SecCFWrappers.h>
26#include <SecureObjectSync/SOSAccountPriv.h>
27
28
29void AppendCircleKeyName(CFMutableArrayRef array, CFStringRef name) {
30    CFStringRef circle_key = SOSCircleKeyCreateWithName(name, NULL);
31    CFArrayAppendValue(array, circle_key);
32    CFReleaseNull(circle_key);
33}
34
35//
36//
37// MARK: KVS Keys
38// TODO: Handle '|' and "¬" in other strings.
39//
40const CFStringRef kSOSKVSKeyParametersKey = CFSTR(">KeyParameters");
41const CFStringRef kSOSKVSInitialSyncKey = CFSTR("^InitialSync");
42const CFStringRef kSOSKVSAccountChangedKey = CFSTR("^AccountChanged");
43
44const CFStringRef sWarningPrefix = CFSTR("!");
45const CFStringRef sAncientCirclePrefix = CFSTR("@");
46const CFStringRef sCirclePrefix = CFSTR("o");
47const CFStringRef sRetirementPrefix = CFSTR("-");
48const CFStringRef sCircleSeparator = CFSTR("|");
49const CFStringRef sFromToSeparator = CFSTR(":");
50
51static CFStringRef copyStringEndingIn(CFMutableStringRef in, CFStringRef token) {
52    if(token == NULL) return CFStringCreateCopy(NULL, in);
53    CFRange tokenAt = CFStringFind(in, token, 0);
54    if(tokenAt.location == kCFNotFound) return NULL;
55    CFStringRef retval = CFStringCreateWithSubstring(NULL, in, CFRangeMake(0, tokenAt.location));
56    CFStringDelete(in, CFRangeMake(0, tokenAt.location+1));
57    return retval;
58}
59
60SOSKVSKeyType SOSKVSKeyGetKeyTypeAndParse(CFStringRef key, CFStringRef *circle, CFStringRef *from, CFStringRef *to)
61{
62    SOSKVSKeyType retval = kUnknownKey;
63
64    if(CFStringHasPrefix(key, sCirclePrefix)) retval = kCircleKey;
65    else if(CFStringHasPrefix(key, sRetirementPrefix)) retval = kRetirementKey;
66    else if(CFStringHasPrefix(key, kSOSKVSKeyParametersKey)) retval = kParametersKey;
67    else if(CFStringHasPrefix(key, kSOSKVSInitialSyncKey)) retval = kInitialSyncKey;
68    else if(CFStringHasPrefix(key, kSOSKVSAccountChangedKey)) retval = kAccountChangedKey;
69    else retval = kMessageKey;
70
71    switch(retval) {
72        case kCircleKey:
73            if (circle) {
74                CFRange fromRange = CFRangeMake(1, CFStringGetLength(key)-1);
75                *circle = CFStringCreateWithSubstring(NULL, key, fromRange);
76            }
77            break;
78        case kMessageKey: {
79            CFStringRef mCircle = NULL;
80            CFStringRef mFrom = NULL;
81            CFStringRef mTo = NULL;
82            CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key);
83
84            if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) &&
85               ((mFrom = copyStringEndingIn(keycopy, sFromToSeparator)) != NULL) &&
86               (CFStringGetLength(mFrom) > 0)  ) {
87                mTo = copyStringEndingIn(keycopy, NULL);
88                if (circle && mCircle) *circle = CFStringCreateCopy(NULL, mCircle);
89                if (from && mFrom) *from = CFStringCreateCopy(NULL, mFrom);
90                if (to && mTo) *to = CFStringCreateCopy(NULL, mTo);
91            } else {
92                retval = kUnknownKey;
93            }
94            CFReleaseNull(mCircle);
95            CFReleaseNull(mFrom);
96            CFReleaseNull(mTo);
97            CFReleaseNull(keycopy);
98        }
99            break;
100        case kRetirementKey: {
101            CFStringRef mCircle = NULL;
102            CFStringRef mPeer = NULL;
103            CFMutableStringRef keycopy = CFStringCreateMutableCopy(NULL, 128, key);
104            CFStringDelete(keycopy, CFRangeMake(0, 1));
105            if( ((mCircle = copyStringEndingIn(keycopy, sCircleSeparator)) != NULL) &&
106               ((mPeer = copyStringEndingIn(keycopy, NULL)) != NULL)) {
107                if (circle) *circle = CFStringCreateCopy(NULL, mCircle);
108                if (from) *from = CFStringCreateCopy(NULL, mPeer);
109            } else {
110                retval = kUnknownKey;
111            }
112            // TODO - Update our circle
113            CFReleaseNull(mCircle);
114            CFReleaseNull(mPeer);
115            CFReleaseNull(keycopy);
116        }
117            break;
118        case kAccountChangedKey:
119        case kParametersKey:
120        case kInitialSyncKey:
121        case kUnknownKey:
122            break;
123    }
124
125    return retval;
126}
127
128
129SOSKVSKeyType SOSKVSKeyGetKeyType(CFStringRef key)
130{
131    return SOSKVSKeyGetKeyTypeAndParse(key, NULL, NULL, NULL);
132}
133
134CFStringRef SOSCircleKeyCreateWithCircle(SOSCircleRef circle, CFErrorRef *error)
135{
136    return SOSCircleKeyCreateWithName(SOSCircleGetName(circle), error);
137}
138
139
140CFStringRef SOSCircleKeyCreateWithName(CFStringRef circleName, CFErrorRef *error)
141{
142    if(!circleName) return NULL;
143    return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), sCirclePrefix, circleName);
144}
145
146CFStringRef SOSCircleKeyCopyCircleName(CFStringRef key, CFErrorRef *error)
147{
148    CFStringRef circleName = NULL;
149
150    if (kCircleKey != SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL)) {
151        SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find circle name in key '%@'"), key);
152
153        CFReleaseNull(circleName);
154    }
155
156    return circleName;
157}
158
159CFStringRef SOSMessageKeyCopyCircleName(CFStringRef key, CFErrorRef *error)
160{
161    CFStringRef circleName = NULL;
162
163    if (SOSKVSKeyGetKeyTypeAndParse(key, &circleName, NULL, NULL) != kMessageKey) {
164        SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find circle name in key '%@'"), key);
165
166        CFReleaseNull(circleName);
167    }
168    return circleName;
169}
170
171CFStringRef SOSMessageKeyCopyFromPeerName(CFStringRef messageKey, CFErrorRef *error)
172{
173    CFStringRef fromPeer = NULL;
174
175    if (SOSKVSKeyGetKeyTypeAndParse(messageKey, NULL, &fromPeer, NULL) != kMessageKey) {
176        SOSCreateErrorWithFormat(kSOSErrorNoCircleName, NULL, error, NULL, CFSTR("Couldn't find from peer in key '%@'"), messageKey);
177
178        CFReleaseNull(fromPeer);
179    }
180    return fromPeer;
181}
182
183CFStringRef SOSMessageKeyCreateWithCircleNameAndPeerNames(CFStringRef circleName, CFStringRef from_peer_name, CFStringRef to_peer_name)
184{
185    return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@%@"),
186                                    circleName, sCircleSeparator, from_peer_name, sFromToSeparator, to_peer_name);
187}
188
189CFStringRef SOSMessageKeyCreateWithCircleAndPeerNames(SOSCircleRef circle, CFStringRef from_peer_name, CFStringRef to_peer_name)
190{
191    return SOSMessageKeyCreateWithCircleNameAndPeerNames(SOSCircleGetName(circle), from_peer_name, to_peer_name);
192}
193
194CFStringRef SOSMessageKeyCreateWithCircleAndPeerInfos(SOSCircleRef circle, SOSPeerInfoRef from_peer, SOSPeerInfoRef to_peer)
195{
196    return SOSMessageKeyCreateWithCircleAndPeerNames(circle, SOSPeerInfoGetPeerID(from_peer), SOSPeerInfoGetPeerID(to_peer));
197}
198
199CFStringRef SOSMessageKeyCreateFromPeerToTransport(SOSTransportMessageKVSRef transport, CFStringRef peer_name) {
200    CFErrorRef error = NULL;
201    SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport);
202
203    CFStringRef circleName = SOSTransportMessageKVSGetCircleName(transport);
204    CFStringRef my_id = SOSEngineGetMyID(engine);
205
206    CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, peer_name, my_id);
207    CFReleaseSafe(error);
208    return result;
209}
210
211CFStringRef SOSMessageKeyCreateFromTransportToPeer(SOSTransportMessageKVSRef transport, CFStringRef peer_name) {
212    CFErrorRef error = NULL;
213    SOSEngineRef engine = SOSTransportMessageGetEngine((SOSTransportMessageRef)transport);
214
215    CFStringRef circleName = SOSTransportMessageKVSGetCircleName(transport);
216    CFStringRef my_id = SOSEngineGetMyID(engine);
217
218    CFStringRef result = SOSMessageKeyCreateWithCircleNameAndPeerNames(circleName, my_id, peer_name);
219    CFReleaseSafe(error);
220    return result;
221}
222
223CFStringRef SOSRetirementKeyCreateWithCircleNameAndPeer(CFStringRef circle_name, CFStringRef retirement_peer_name)
224{
225    return CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@%@%@"),
226                                    sRetirementPrefix, circle_name, sCircleSeparator, retirement_peer_name);
227}
228
229CFStringRef SOSRetirementKeyCreateWithCircleAndPeer(SOSCircleRef circle, CFStringRef retirement_peer_name)
230{
231    return SOSRetirementKeyCreateWithCircleNameAndPeer(SOSCircleGetName(circle), retirement_peer_name);
232}
233
234