Prevent original files from OS X app's sandbox container to be modified via drag and drop or Share Extensions? - macos

I have a shoebox type (as opposed to document based) OS X app that stores images in the app's sandbox container.
These images can be shared via Share Extensions (in form of a NSURL) or exported via drag and drop.
When an image is shared to an image editor (e.g. Acorn offers a Share Extension), or dropped on an image editor, the image editor opens the file from within my sandbox container and can now alter, rename or delete this file - which can lead to all kinds of inconstancies in my app.
First, I was surprised, because I thought, files in the sandbox can only be accessed by the app itself. But it seems this is not the case, when I intentionally share the NSURL.
So how can I prevent that someone can alter files in my sandbox container while still offering them for drag and drop and to Share Extensions?
I tried not sharing NSURLs but NSImages, but many Share Extensions do not work with NSImages, so this is not a good option.
Is it a possibility to write-protect the files in the sandbox?
Should I always make a copy of an image to a temporary location, before I offer it for sharing or drag and drop (could be slow for big images?)
I am happy to hear your suggestions or learn more about the problem.

Create a bookmark of the NSURL.
So the user can still rename, move and delete the file, but you notice it and know the new location and name and still are able to access the file. Should work even if it's outside your sandbox.
So you can handle this.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSURL_Class/
That's one of the benefits working with NSURL and not with a simple path string.

Related

Can an app-scoped security scoped bookmark be copied from one Mac to another?

I have a sandboxed application that uses a document format which can contain embedded filenames. E.g. some of these referenced files are for image files which the user selects in order to associate the image file with data stored in the document. Whilst such images will sometimes be located in the users pictures folder, sometimes they are elsewhere. The document format itself cannot be changed for portability reasons (it is shared with an existing Windows version of the app).
In order for the app to be able to access the files whose names are embedded within the document, when the user selects a filename (using nsopenpanel) to be stored in the document like this, the app also creates an app-scoped security scoped bookmark for each such stored filename. It then stores these bookmarks by serialising them to another file. When the app runs again it loads its previously serialised bookmarks and uses them when accessing the 'embedded' filename and that works fine.
But when I copy such a document (and its associated serialised bookmarks file) from one Mac to another, it doesnt work, even though all the files the bookmarks refer to are known to exist on both Macs. What happens is that whilst the app opens the document file ok (after the user selected it with an nsopenpanel), and successfully reads in the serialised bookmarks from its associated serialised bookmarks file (which again the user has selected using nsopenpanel), and even though the exact same filenames that the bookmarks refer to are known to exist on the other Mac (and can be accessed by the user through finder etc), the sandboxed app still cannot access them. Resolving the bookmarks seems to fail.
The question is: are app-scoped bookmarks restricted to only working on the Mac on which they were created? If I cannot move an app-scoped bookmark from one system to another, how else can I achieve the effect I want without forcing the user to have to manually re-select every such 'embedded' filename with an nsopenpanel?
Tried to find the answer to this question in the Apple docs without success.
I take it it goes without saying that security-scoped bookmarks can only be used by the app that creates them.
No, because if this were possible, developers could save security-scoped bookmarks to sensitive files/directories on their own computers and then deploy their apps and have access to those same sensitive files/directories on other peoples' computers.

Where does getExternalFilesDir() point to in an app running in Chrome?

I've successfully got my app running in Chrome using arc welder. And having managed to identify which files hold the sqlite database and shared preferences, I've been able to copy those across to nicely replicate how the app works on my 'phone.
On the 'phone, my app can take photographs, which it stores in the path found using getExternalFilesDir(null) and it would be nice to be able to copy those over so they can be seen when using the app through Chrome. But searching around, I've been unable to work out where this is.
I can save a file (using the app's database exporter and file-chooser) to somewhere which appears as an SD card, but no file or directory under my app's directory in ~/.config/google-chrome/Default/Storage/ext which gets changed when I do the export seems to fit.
I can see the exported file's name in def/File System/primary/p/Paths/000004.log, though as that's a data file it's not giving me any clues.
Anybody know where the virtual SD card (and so externalFilesDir) might be held?
By default ARC stores the external storage files to the Chrome HTML5 filesystem. Each app gets its own instance of the filesystem.
To put files into it, you can either:
(On a PC only) start your app, visit "chrome://inspect/#apps" for your app, and type plugin.shell('adbd') into the javascript console for it. Then you can use the Android ADB command adb push ... to transfer the data.
Or you can also add {"enableExternalDirectory": true} to your application's metadata. Enabling this option means that ARC will prompt you for the directory to use for for the external directory, and you can pick a real directory on your system to use.

Display PDF file in LocalState folder in Windows 8 app in Cordova

My application downloads a PDF and stores it in the LocalState folder for my Windows 8 app.
I have a link within the app that I would like to show the PDF when the user clicks it.
I've tried displaying it using ms-appdata:///local/pdfs/filename.pdf in a window.open call and I also tried using the InAppBrowser plugin within cordova with no luck. Additionally, I've tried the following:
var uri = new Windows.Foundation.Uri('ms-appdata:///local/pdfs/filename.pdf');
var file = Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri);
Windows.System.Launcher.launchFileAsync(file).done();
I know the file exists as I'm getting a file result back. Just not sure how to allow the user to view it.
By design, the local appdata folder on Windows is accessible only to that app, or to full-trust desktop applications (and this is probably true of similar sandboxed locations on other platforms). As a result, a Windows Store app that gets launched with Launcher.launchFileAsync won't be able access that location (nor can a webview process, which is also sandboxed). If a desktop application gets launched, on the other hand, it probably can access the file, but you can't tell ahead of time if that's the case. Bottom line is that local appdata isn't a good location for letting other apps get at the file.
You'll need to save the file in another location that is accessible to other apps. There are two approaches here, both of which will require a little user interaction to select a location, so they can place the PDFs anywhere they want:
Have the user select a save folder for your app, which they can do once. You would invoke the FolderPicker for this purpose, and save the selected folder in the FutureAccessList. This way you can have the user select the save folder, which grants you consent to save there, and by saving it in the FutureAccessList you can retrieve it in subsequent sessions without having to ask the user again. Refer to the File Picker Sample and the File Access Sample for more.
Have the user select a save location for each individual file, using the FilePicker (see the same sample), and you can also use the access cache to save permissions to those individual locations if you need them later.
There might be Cordova plugins that work with these APIs too, but I haven't checked. Either way, once the file is in an accessible location, launching the file should work just fine.
As an alternate solution, you could consider rendering the PDFs directly in your app. Windows has an API for this in Windows.Data.Pdf, with an associated sample. There might be a plugin or other JS libraries that could also work for this.

How can I associate a file with my app?

I have a Cocoa app "PDFHistory" on Mac OS X that uses the NSDocument architecture to save and load PDF files that are internally formatted specially for my app. I want to make it so whenever I save a file (e.g., "mydoc.pdf") from PDFHistory, then subsequently double-clicking on mydoc.pdf will automatically open it in PDFHistory.app. However, I don't want to make it so all .pdf files are automatically opened in PDFHistory, but rather use the system default (probably Preview.app). The .pdf suffix is a requirement, though, since I need the user to be able to e-mail the files to other users who can view the file in their default PDF viewer.
The problem is that if I set the LSHandlerRank to "Owner", then all .pdf files will be opened with PDFHistory, which is bad (since I only understand the internals of the .pdf file that PDFHistory wrote out). But if I set LSHandlerRank to "Alternate", then all .pdf files will be opened to the system default app (Preview.app), which is confusing for the user who had just created the file using my app.
Once upon a time, "creator codes" could be used to implement this sort of capability, but launch services started ignoring them back in Snow Leopard (see http://tidbits.com/article/10537). UTIs are not a substitute that provide this capability (see http://boredzo.org/blog/archives/2009-09-22/how-not-to-use-utis).
Using Finder to get info on the file allows the user to specify a specific app to use to open the specific file. This supposedly works by setting a "usro" property in a the file's resource. There is some open-source code to mimic this behavior (https://github.com/AlanQuatermain/SetAppAffinity), but is uses deprecated functions, and so would cause Apple to reject the app from the App Store. Similarly, people have posted AppleScript to set this property (https://discussions.apple.com/thread/2597365), but sandboxing would prevent me from invoking it.
Although the .pdf suffix is a requirement in order to be able to send the files to users on other systems/platforms, I considered trying to have the suffix registered with two extensions as ".phistory.pdf", which would allow "file.phistory.pdf" to be opened in PDFHistory, but "file.pdf" would be opened in the default PDF viewer. However, this simply didn't work: it appears that the final suffix is the only one used by launch services, and everything before that is ignored.
So is there any way to have my app be the default app for opening files that it created itself?

Creating a local folder through an url

imagine you want to have a link on a website that creates a local folder and opens it in the Windows Explorer as soon as click on it. Something like Go to new folder
I know there is the file:-protocol, but this only opens a local folder. Is there a way to specify in the url that the browser should also create the folder.
It might be against lot's of security policies. But I'm just curious if there is any way you could achieve that. What ever come in your mind? Don't hold back.
Cheers,
Gerardo
As you mentioned, this is not allowed for web pages from internet. (imagine a rogue script running thousands of these)
You may be able to open an existing folder, in the browser (not via Windows Explorer, unless it's IE and the page is trusted).
If you want to create a folder, try using Offline Storage APIs for HTML5. This may not accomplish the 'opening in Win Explorer' part, but you can store data on user's machine.
Hope this helps.

Resources