WebExtensions/Filesystem
Overview
The ability to read and write from the file system has been one of the more controversial topics with WebExtensions. In the past this has been available to legacy extensions through APIs like OS.File and OS.File.DirectoryIterator: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/OSFile.jsm ... and this has allowed extensions to read and write from the file system with no limits.
The goal behind WebExtensions is to provide a safe, secure, sandboxed environment for our users and as such file system access provides a direct challenge to the sandbox. As such we should examine any APIs around file system access carefully.
The main driver of trying to explain this is bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1246236
Chrome
Chrome provides the File System Storage API as documented at: https://developer.chrome.com/apps/app_storage
However this API is targeted at Chrome OS and will be removed in Chrome. Currently 1,424 apps out of 37,652 ask for file system access. No word has been given of a replacement at this time. Firefox has not been implementing app APIs for extensions, but only implementing extension APIs.
There is the isAllowedFileSchemeAccess which is documented at: https://developer.chrome.com/extensions/extension#method-isAllowedFileSchemeAccess this allows you to access the contents of file:// locations, as you can other protocols (http and https). It’s effectively read access to the file system.
To enable it a user has to go to chrome://extensions and give the add-on that permission. Currently 55 out of approx. 58,000 extensions on the chrome store use that API.
Firefox
Just copying Chrome or providing the same access in the past to extensions is a general cause of concern to most the add-ons engineering team.
WebAPI
Currently there is https://developer.mozilla.org/en-US/docs/Web/API/File_and_Directory_Entries_API which is a non-standard API. It only allows read access to a file when using an <input> element or drag and drop.
In the past
There are many extensions that use OS.File and other APIs. This doesn’t mean they automatically should continue to do so in the future. Along with the file system sandboxing initiative being carried out by Firefox, we’d like to focus on user security and privacy first.
Just a big button
The main suggestion seems to be “just add a big button” to let users choose that they can give file system access. The problem is that we have to ensure users understand the risk of what they are giving to the extension. An extension that can read from your file system can at the read through your profile and access all data such as cookies, passwords and history you've been able to break out the sandbox. And that's just what you can gleam from Firefox files.
Just copy chrome
We’ve done pretty well on Chrome parity but refuse to do something just because Chrome has, especially if we feel that feature has a major security or privacy risk. This is one of those.
= Explicit user interaction
We believe that if an extension is going to interact with a file then it should be done in a clear and understandable way for the user. For that we focus on explicit user actions, like drag and drop or file picker. UX flows that the user is already familiar with.
Opera
Opera supports isAllowedFileSchemeAccess, although I haven’t confirmed this. I tried this with an extension and Opera crashed.
Edge
Not supported according to the docs: https://docs.microsoft.com/en-us/microsoft-edge/extensions/api-support/supported-apis
Use Cases
We’ve tried to focus on some use cases that extension authors have presented to us. Sadly they don’t meet every need, but should solve some common use cases.
The downloads API
It should be noted that Firefox currently implements the downloads API: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/downloads
This allows add-ons to write files and data to the file system in a consistent manner with an understandable user interface. Files are only written into the users downloads directory.
The downloads API is not accessible from the content process, preserving the file system sandboxing requirements.
Streaming downloads into the downloads directory
If you have an extension which assists in downloading large files, using the download API can be cumbersome as you might have to read the file into memory before processing it further. By implementing a streaming API for Firefox, we hope to allow efficient processing of large downloads in Firefox:
https://bugzilla.mozilla.org/show_bug.cgi?id=1323414
Choosing location in the downloads directory
Currently an extension cannot choose to download a file into a particular location for file name based on rules from the extension. For this, Firefox will need to implement the onDeterminingFilename API that Chrome supports:
https://bugzilla.mozilla.org/show_bug.cgi?id=1245652
Writing outside the downloads directory
The downloads API is limited to just the downloads directory. If the downloads could write outside the directory, then you’ve effectively got write access anywhere that the process can write too.
The problem here is giving a prompt that is understandable to the user. There is quite a difference from the user picking a directory and the extension presenting a directory to the user.
https://bugzilla.mozilla.org/show_bug.cgi?id=1331618
Blob storage
Some extensions just want somewhere to store data in a profile and have persist between restarts of Firefox. Example extensions are photo editors. For this we have an indexedDB store than take files of up to 20 gb, with user permission.
The extension is then able to store, load and manipulate those files efficiently and remain securely inside the WebExtensions and Firefox sandbox.
We’d like to ensure that a large storage is available, with appropriate prompting for the user. We’d like to provide a library that makes using this storage easy from an extension.
https://bugzilla.mozilla.org/show_bug.cgi?id=1331618 https://github.com/mdn/webextensions-examples/pull/171
Drag and drop, file picker support
These should be critical parts of our WebExtension infrastructure as they ensure the easiest way to provide read access to files. Currently we are prototyping and check this to see if there’s anything else we should do.
The use case here is similar to dropping a PDF on Firefox, which opens a pdf tab using the builtin reader. Similar use cases would be doing the same with ePub files. Proper support for this use case would require some modification of content handlers, or the hack work around used by pdfjs (a fake plugin).
One could also drop a directory into a sidebar as a way to gain access to a list of files (ie. project directory) for something like a local wiki page editor, though write access would be an issue for that use case.
From a file picker and drag and drop you can get access to files and their contents. You can get access to directories if you set a pref dom.input.filePicker and using webkitdirectory=true as per https://bugzilla.mozilla.org/show_bug.cgi?id=1164310
Engineering Plan
Firefox 57
These are the things we plan on doing by Firefox 57:
- Streaming downloads
- A library based on indexedDB for blob storage and the appropriate support.
- Providing documentation on:
- What choices are available and why
- How to handle drag and drop in an extension
- How to use file picker support
- How to use the indexedDB blob storage library
- How to use nativeMessaging with downloads API to do processing
Not planned
These might be possible, but are too large to reasonably commit too and have too many unanswered security and usability questions:
- Writing outside the downloads directory
- Access to file:// URLs or reading files without any explicit user input