NSFileProtection confusion

Hello.


I have an CoreData app that explicitly enables the data protection capability and sets "NSFileProtectionComplete" in the entitlements. However, if I check the file attributes on the 3 files of the sqlite database I see that these are set to "NSFileProtectionCompleteUntilFirstUserAuthentication" The parent directory ("Application Support") is correctly set to "NSFileProtectionComplete". What am I missing?


BR

Björn

Answered by NotMyName in 305399022

For NSPersistentContainer, you have to configure a NSPersistentStoreDescription object, use setOption( forKey:) to set the NSPersistentStoreFileProtectionKey option, and put that in the persistentStoreDescriptions. I'm not sure if that means you'll have to fill out all of the other properties of the StoreDescription.


For strange reasons, Core Data chooses to default to completeUntilFirstUserAuthentication instead of what the app is set to. But, according to the documentation for the persistent store option:

"Backward compatibility may preclude some features. The acceptable values are those defined for the

protectionKey
. The default value is
completeUntilFirstUserAuthentication
for all applications built on or after iOS v5.0. The default value for all older applications is
none
."

I have an CoreData app that explicitly enables the data protection capability …

Via the Core Data API? That is,

NSPersistentStoreFileProtectionKey
? Please post a snippet of code that shows how you’re doing that.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi. I use the CoreData template provided by Apple:

lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: "MyPersistentStore")
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            NSLog("Store description: \(storeDescription)")
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }
        })
        return container
    }()

How/where do I set the NSPersistentStoreFileProtectionKey in this case?


Best regards

Björn

Accepted Answer

For NSPersistentContainer, you have to configure a NSPersistentStoreDescription object, use setOption( forKey:) to set the NSPersistentStoreFileProtectionKey option, and put that in the persistentStoreDescriptions. I'm not sure if that means you'll have to fill out all of the other properties of the StoreDescription.


For strange reasons, Core Data chooses to default to completeUntilFirstUserAuthentication instead of what the app is set to. But, according to the documentation for the persistent store option:

"Backward compatibility may preclude some features. The acceptable values are those defined for the

protectionKey
. The default value is
completeUntilFirstUserAuthentication
for all applications built on or after iOS v5.0. The default value for all older applications is
none
."

I am facing a problem in testing the app. i have set the file protection to Complete for my core data that is saved under the Library of applicaiton sandbox.

To test I tried frinting the attributes of the file and it gives the NSFIleProtectedComplete but still I was able to view the sqlite file when I downloaded the container. I guess in one of the post it says that if the compture is trusted you will see the data. Then I read here https://forums.developer.apple.com/thread/47910?q=file%20protection

and used iExporer and also read the document suggested in the reply but reading about keybags doenst solve the problem on testing.


Do I need to install the app on App store? Can I install the app on Hockecy and test it ?

Can i install the app on iTunesConnect and test it ?


Or printing the attributes of the file and checking the protection class completes the testing?

Thanks in advance.

Amit

I use the CoreData template provided by Apple...

I got the following code to work:

Code Block
let container = NSPersistentContainer(name: "MyApp")
let storeDirectory = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
let url = storeDirectory.appendingPathComponent("MyApp.sqlite")
let description = NSPersistentStoreDescription(url: url)
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
description.setOption(FileProtectionType.completeUnlessOpen as NSObject, forKey: NSPersistentStoreFileProtectionKey)
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in ... }


Here's a working snippet:

container = NSPersistentCloudKitContainer(name: "YourDataModelName")
container.persistentStoreDescriptions.first!.setOption(FileProtectionType.complete as NSObject, forKey: "NSPersistentStoreFileProtectionKey")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
...
NSFileProtection confusion
 
 
Q