An amazing project that generates micro reports from tournament results
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
5.7 KiB

////////////////////////////////////////////////////////////////////////////
//
// Copyright 2014 Realm Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
#import "LabelViewController.h"
#import <Realm/Realm.h>
#import <Security/Security.h>
// Model definition
@interface StringObject : RLMObject
@property NSString *stringProp;
@end
@implementation StringObject
// Nothing needed
@end
@interface LabelViewController ()
@property (nonatomic, strong) UITextView *textView;
@end
@implementation LabelViewController
// Create a view to display output in
- (void)loadView {
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame];
contentView.backgroundColor = [UIColor whiteColor];
self.view = contentView;
self.textView = [[UITextView alloc] initWithFrame:applicationFrame];
[self.view addSubview:self.textView];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// Use an autorelease pool to close the Realm at the end of the block, so
// that we can try to reopen it with different keys
@autoreleasepool {
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.encryptionKey = [self getKey];
RLMRealm *realm = [RLMRealm realmWithConfiguration:configuration
error:nil];
// Add an object
[realm beginWriteTransaction];
StringObject *obj = [[StringObject alloc] init];
obj.stringProp = @"abcd";
[realm addObject:obj];
[realm commitWriteTransaction];
}
// Opening with wrong key fails since it decrypts to the wrong thing
@autoreleasepool {
uint8_t buffer[64];
int status = SecRandomCopyBytes(kSecRandomDefault, 64, buffer);
NSAssert(status == 0, @"Failed to generate random bytes for key");
(void)status;
NSError *error;
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.encryptionKey = [[NSData alloc] initWithBytes:buffer length:sizeof(buffer)];
[RLMRealm realmWithConfiguration:configuration
error:&error];
[self log:@"Open with wrong key: %@", error];
}
// Opening wihout supplying a key at all fails
@autoreleasepool {
NSError *error;
[RLMRealm realmWithConfiguration:[RLMRealmConfiguration defaultConfiguration] error:&error];
[self log:@"Open with no key: %@", error];
}
// Reopening with the correct key works and can read the data
@autoreleasepool {
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.encryptionKey = [self getKey];
RLMRealm *realm = [RLMRealm realmWithConfiguration:configuration
error:nil];
[self log:@"Saved object: %@", [[[StringObject allObjectsInRealm:realm] firstObject] stringProp]];
}
}
// Log a message to the screen since we can't just use NSLog() with no debugger attached
- (void)log:(NSString *)format, ... {
va_list args;
va_start(args, format);
NSString *str = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
self.textView.text = [[self.textView.text
stringByAppendingString:str]
stringByAppendingString:@"\n\n"];
}
- (NSData *)getKey {
// Identifier for our keychain entry - should be unique for your application
static const uint8_t kKeychainIdentifier[] = "io.Realm.EncryptionExampleKey";
NSData *tag = [[NSData alloc] initWithBytesNoCopy:(void *)kKeychainIdentifier
length:sizeof(kKeychainIdentifier)
freeWhenDone:NO];
// First check in the keychain for an existing key
NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassKey,
(__bridge id)kSecAttrApplicationTag: tag,
(__bridge id)kSecAttrKeySizeInBits: @512,
(__bridge id)kSecReturnData: @YES};
CFTypeRef dataRef = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataRef);
if (status == errSecSuccess) {
return (__bridge NSData *)dataRef;
}
// No pre-existing key from this application, so generate a new one
uint8_t buffer[64];
status = SecRandomCopyBytes(kSecRandomDefault, 64, buffer);
NSAssert(status == 0, @"Failed to generate random bytes for key");
NSData *keyData = [[NSData alloc] initWithBytes:buffer length:sizeof(buffer)];
// Store the key in the keychain
query = @{(__bridge id)kSecClass: (__bridge id)kSecClassKey,
(__bridge id)kSecAttrApplicationTag: tag,
(__bridge id)kSecAttrKeySizeInBits: @512,
(__bridge id)kSecValueData: keyData};
status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
NSAssert(status == errSecSuccess, @"Failed to insert new key in the keychain");
return keyData;
}
@end