Site icon JoinAppStudio

Read and Write Data in a Sandboxed App (Part 1)

Read and Write Data in a Sandboxed App (Part 1)

If you are developing a Mac app you may need to read and write files to the user’s Mac folders, outside of the app container.

I found myself in the same situation many times. So in this guide I want to share what is my understanding of this topic so far.

I gathered this information across forums, tutorials and the Apple documentation.

This is a vast topic that involves also user privacy and security of its data, in this guide we will cover only the actual implementation of the reading and writing process.

App Sandbox

What is the App Sandbox?

Apple’s Documentation states that:

App Sandbox is used to) Restrict access to system resources and user data in macOS apps to contain damage if an app becomes compromised. App Sandbox provides protection to system resources and user data by limiting your app’s access to resources requested through entitlements.

The app sandbox is meant to keep users safe from apps that contain malicious code or contain vulnerabilities that an attacker can exploit for malicious purposes. The sandbox protects users’ assets from damage or theft.

Apple now mandates app sandboxing in iOS and macOS apps.

To distribute a macOS app through the Mac App Store, you must enable the App Sandbox capability.

So, the App Sandbox is like a wall that surrounds our app and lets us communicate only with the external resources that the user grant us permission.

Setup App Sandbox

To configure the App Sandbox, go to your Target and under Signin & Capabilities you should already see App Sandbox.

If that’s not the case, hit the + button and search and add App Sandbox.

You should also see the Hardened Runtime, basically this is another security capability that protects the integrity of the software.

Apple’s Documentation states that:

The Hardened Runtime, along with System Integrity Protection (SIP), protects the runtime integrity of your software by preventing certain classes of exploits, like code injection, dynamically linked library (DLL) hijacking, and process memory space tampering.

Now, back to our App Sandbox.

Under App Sandbox you can see a lot of options, in this guide we will look at the File Access section.

These options controls, at a high level, which folders your app can ask permission to read, write or both.

This doesn’t mean that by selecting read/write for User Selected File in the App Sandbox settings, you can access those folders right away. But you still need to ask the user to give you permission to read/write to those folder.

Sandboxed vs. Un-sandboxed app

Say we need to create a file in the user’s Desktop.

In an un-sandboxed app you can simply call write(to:)

try data.write(to: fileURL)

And you’re done.

In a sandboxed app, instead, if we do the same process, the function returns an error that looks like this:

You don't have permission to write to user folder.

This happens because in a sandboxed app you can only write to and read from the folders in the app’s container.

This is one of Apple’s methods for limiting the vulnerable surface area of the app to attack by malware.

Write from a sandboxed app

Now that we saw what is the behaviour of sandboxed and un-sandboxed app, let’s see how to actually write from a sandboxed app.

Since we want to write to a non-default folder (like Downloads, Images, …), we need to ask the user where to save our file.

So, in TARGETS -> [TARGET_NAME] -> Signing & Capabilities -> App Sandbox -> File Access -> Type -> User Selected File change Permission & Access from None to Read/Write.

This will add the com.apple.security.files.user-selected.read-write entitlement to your project.

Ask where to save the file

Now, before to write the file, we must ask the user where he wants to save the file. We will do this using the NSOpenPanel class.

let openPanel = NSOpenPanel()

openPanel.prompt = "Select"

openPanel.message = "Please select a folder"

openPanel.allowedContentTypes = [.directory]

openPanel.canChooseFiles = false

openPanel.allowsOtherFileTypes = false

openPanel.allowsMultipleSelection = false

openPanel.canChooseDirectories = true

// Open the modal folder selection panel.

let okButtonPressed = openPanel.runModal()

if okButtonPressed == .OK {

// If the user doesn't select anything, then the URL \"file:///\" is returned, which we ignore

if let url = openPanel.urls.first,

url.absoluteString != "file:///" {

print("User selected folder: \\(url)")

// Persist user selected folder for later launches

} else {

print("User did not select a folder")

}

} else {

print("User cancelled folder selection panel")

}

Note

This is a synchronous process even if there is user interaction. So you don’t need completion blocks to perform actions when the user selects the folder.

Now, once the user selected the folder, you can write like we did in the un-sandboxed app.

let fileURL = URL(fileURLWithPath: "file_name.json", relativeTo: selectedFolderURL)

try data.write(to: fileURL)

Persist user intent across launches

See how to persist the selected folder, so in the next launches you don’t have to ask permission again. And the user will have a smoother experience.

How to persist user folders permission

Conclusion

I hope I’ve helped you understand how the sandbox works and how to read and write files outside of the app container.

Source link

Exit mobile version