Skip to content
This repository has been archived by the owner on Sep 12, 2019. It is now read-only.

Set up an encrypted iOS Database with only 1 line of code!

License

Notifications You must be signed in to change notification settings

flipacholas/EncryptedDATAStack

Repository files navigation

EncryptedDATAStack

CI Status Version License Platform

Set up an encrypted Database with only 1 line of code!

EncryptedDATAStack is a fork of DATAStack with added support of Encrypted Core Data (Core Data + SQLCipher) and extra legacy support for iOS 8. All in all, this allows you to set up a database (encrypted and/or unencrypted) with only one line of code!

Version tags are set to match the version of DATAStack used.

Table of Contents

Running the demo

Before being able to run the demo you have to install the demo dependencies using CocoaPods.

  • Install CocoaPods
  • Type pod install
  • Run Example workspace

Initialization

You can easily initialize a new instance of EncryptedDATAStack with just your Core Data Model name (xcdatamodel).

Swift

let encryptedDataStack = EncryptedDATAStack(passphraseKey:"YOUR_PASSWORD", modelName:"MyAppModel")

Objective-C

EncryptedDATAStack *encryptedDataStack = [[EncryptedDATAStack alloc] initWithPassphraseKey:@"YOUR_PASSWORD" modelName:@"MyAppModel"];

There are plenty of other ways to intialize an EncryptedDATAStack:

  • Using a custom store type.
//For Memory Storage
let encryptedDataStack = EncryptedDATAStack(modelName:"MyAppModel", storeType: .InMemory)
//For Regular SQLite
let encryptedDataStack = EncryptedDATAStack(modelName:"MyAppModel", storeType: .sqLiteNoEncryption)
  • Using another bundle and a store type, let's say your test bundle and .InMemory store type, perfect for running unit tests.
let encryptedDataStack = EncryptedDATAStack(modelName: "Model", bundle: NSBundle(forClass: Tests.self), storeType: .InMemory)
  • Using a different name for your .sqlite file than your model name, like CustomStoreName.sqlite.
let encryptedDataStack = EncryptedDATAStack(passphraseKey:"YOUR_PASSWORD", modelName: "Model", bundle: NSBundle.mainBundle(), storeType: .sqLite, storeName: "CustomStoreName")
  • Providing a diferent container url, by default we'll use the documents folder, most apps do this, but if you want to share your sqlite file between your main app and your app extension you'll want this.
let encryptedDataStack = EncryptedDATAStack(passphraseKey:"YOUR_PASSWORD", modelName: "Model", bundle: NSBundle.mainBundle(), storeType: .sqLite, storeName: "CustomStoreName", containerURL: sharedURL)

Main Thread NSManagedObjectContext

Getting access to the NSManagedObjectContext attached to the main thread is as simple as using the mainContext property.

self.encryptedDataStack.mainContext

or

self.encryptedDataStack.viewContext

Background Thread NSManagedObjectContext

You can easily create a new background NSManagedObjectContext for data processing. This block is completely asynchronous and will be run on a background thread.

To be compatible with NSPersistentContainer you can also use performBackgroundTask instead of performInNewBackgroundContext.

Swift

func createUser() {
self.encryptedDataStack.performInNewBackgroundContext { backgroundContext in
let entity = NSEntityDescription.entityForName("User", inManagedObjectContext: backgroundContext)!
let object = NSManagedObject(entity: entity, insertIntoManagedObjectContext: backgroundContext)
object.setValue("Background", forKey: "name")
object.setValue(NSDate(), forKey: "createdDate")
try! backgroundContext.save()
}
}

Objective-C

- (void)createUser {
[self.encryptedDataStack performInNewBackgroundContext:^(NSManagedObjectContext * _Nonnull backgroundContext) {
NSEntityDescription *entity = [NSEntityDescription entityForName:@"User" inManagedObjectContext:backgroundContext];
NSManagedObject *object = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:backgroundContext];
[object setValue:@"Background" forKey:@"name"];
[object setValue:[NSDate date] forKey:@"createdDate"];
[backgroundContext save:nil];
}];
}

When using Xcode's Objective-C autocompletion the backgroundContext parameter name doesn't get included. Make sure to add it.

Clean up

Deleting the .sqlite file and resetting the state of your EncryptedDATAStack is as simple as just calling drop.

Swift

self.encryptedDataStack.drop()

Objective-C

[self.encryptedDataStack forceDrop];

Testing

EncryptedDATAStack is optimized for unit testing and it runs synchronously in testing enviroments. Hopefully you'll have to use less XCTestExpectations now.

You can create a stack that uses in memory store like this if your Core Data model is located in your app bundle:

Swift

let encryptedDataStack = EncryptedDATAStack(modelName: "MyAppModel", bundle: NSBundle.mainBundle(), storeType: .InMemory)

Objective-C

EncryptedDATAStack *encryptedDataStack = [[EncryptedDATAStack alloc] initWithModelName:@"MyAppModel"
bundle:[NSBundle mainBundle]
storeType:EncryptedDATAStackStoreTypeInMemory];

If your Core Data model is located in your test bundle:

Swift

let encryptedDataStack = EncryptedDATAStack(modelName: "MyAppModel", bundle: NSBundle(forClass: Tests.self), storeType: .InMemory)

Objective-C

EncryptedDATAStack *encryptedDataStack = [[EncryptedDATAStack alloc] initWithModelName:@"MyAppModel"
bundle:[NSBundle bundleForClass:[self class]]
storeType:EncryptedDATAStackStoreTypeInMemory];

Migrations

If EncryptedDATAStack has troubles creating your persistent coordinator because a migration wasn't properly handled or the passphrase was incorrect it will destroy your data and create a new sqlite file. The normal Core Data behaviour for this is making your app crash on start. This is not fun.

Installation

EncryptedDATAStack is available through CocoaPods. To install it, simply add the following line to your Podfile:

use_frameworks!

pod 'EncryptedDATAStack', :git => 'https://github.com/flipacholas/EncryptedDATAStack.git'
pod 'EncryptedCoreData', :git => 'https://github.com/project-imas/encrypted-core-data'

Possible bugs

The latest version might not be suitable for some particular tasks, if you are having problems try the 2.0 branch:

use_frameworks!

pod 'EncryptedDATAStack', '~> 2.0.0'

Improvements

You can open issues, pull requests... I will be happy to help

Author

Rodrigo Copetti, @flipacholas

Special thanks to:

Elvis Nuñez, @3lvis and Project iMAS, project-imas

License

EncryptedDATAStack is available under the Affero GPL v3 Licence.

...Just kidding, MIT license for you. See the LICENSE file for more info.