Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
CIDCloudKeyManager

iOS から iOS への端末移行時、iCloud を用いてセキュアにユーザを紐付けするコード

#import <Foundation/Foundation.h>
@interface CIDCloudKeyManager : NSObject
+ (instancetype)sharedManager;
- (void)startFetchingWithContainerIdentifier:(NSString *)identifier
storingCloudKeyBlock:(void(^)(NSString *cloudKeyID, NSString *cloudKeySecret))storingCloudKeyBlock
paringCloudKeyBlock:(void(^)(NSString *cloudKeyID, NSString *cloudKeySecret))paringCloudKeyBlock;
@end
#import "CIDCloudKeyManager.h"
@import CloudKit;
static NSString *const kCIDCloudKeyRecordID = @"TheCloudKey";
static NSString *const kCIDCloudKeyRecordType = @"CloudKey";
static NSString *const kCIDCloudKeySecretKey = @"secret";
static NSString *CIDMakeRandomKey(int length) {
NSString *alphabet = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXZY0123456789";
NSMutableString *s = [NSMutableString stringWithCapacity:length];
for (NSUInteger i = 0U; i < length; i++) {
u_int32_t r = arc4random() % [alphabet length];
unichar c = [alphabet characterAtIndex:r];
[s appendFormat:@"%C", c];
}
return s.copy;
};
static void CIDSaveCloudKey(NSString *cloudKeyID, NSString *secret) {
NSLog(@"Saving cloud key: %@:%@", cloudKeyID, secret);
}
static void CIDPairCloudKey(NSString *cloudKeyID, NSString *secret) {
NSLog(@"Checking cloud key: %@:%@", cloudKeyID, secret);
}
static CKRecordID *CIDMakeTheCloudKeyRecordID() {
return [[CKRecordID alloc] initWithRecordName:kCIDCloudKeyRecordID];
}
static CKRecord *CIDMakeCloudKeyWithRandomSecret() {
NSString *secret = CIDMakeRandomKey(32);
CKRecord *cloudKey = [[CKRecord alloc] initWithRecordType:kCIDCloudKeyRecordType recordID:CIDMakeTheCloudKeyRecordID()];
[cloudKey setObject:secret forKey:kCIDCloudKeySecretKey];
return cloudKey;
}
@implementation CIDCloudKeyManager
+ (instancetype)sharedManager {
static CIDCloudKeyManager *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[CIDCloudKeyManager alloc] init];
});
return _instance;
}
- (void)startFetchingWithContainerIdentifier:(NSString *)identifier storingCloudKeyBlock:(void (^)(NSString *, NSString *))storingCloudKeyBlock paringCloudKeyBlock:(void (^)(NSString *, NSString *))paringCloudKeyBlock {
CKContainer *container = [CKContainer defaultContainer];
if (identifier != nil) {
container = [CKContainer containerWithIdentifier:identifier];
}
[container fetchUserRecordIDWithCompletionHandler:^(CKRecordID *recordID, NSError *error) {
if (recordID == nil || error != nil) {
NSLog(@"%@", error);
return;
}
NSString *userId = recordID.recordName;
NSLog(@"Found record ID! Try to fetch CloudKey.");
CKDatabase *db = container.privateCloudDatabase;
[db fetchRecordWithID:CIDMakeTheCloudKeyRecordID() completionHandler:^(CKRecord *record, NSError *error) {
if (record != nil) {
NSLog(@"Found!! Should do paring.");
NSString *secret = [record objectForKey:kCIDCloudKeySecretKey];
if (paringCloudKeyBlock != nil) {
paringCloudKeyBlock(userId, secret);
}
return;
}
if ([error.domain isEqualToString:CKErrorDomain] && error.code == CKErrorUnknownItem) {
NSLog(@"Cloud not find CloudKey. Try to create CloudKey.");
CKRecord *cloudKey = CIDMakeCloudKeyWithRandomSecret();
[db saveRecord:cloudKey completionHandler:^(CKRecord *record, NSError *error) {
if (error != nil) {
NSLog(@"Error occured during saving: %@", error);
}
NSLog(@"Complete everything!");
NSString *secret = [record objectForKey:kCIDCloudKeySecretKey];
CIDSaveCloudKey(userId, secret);
if (storingCloudKeyBlock != nil) {
storingCloudKeyBlock(userId, secret);
}
}];
} else {
NSLog(@"Unknown error occured. Should retry?");
}
}];
}];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment