Status: THIS IS A DRAFT, more to come.
- 1 Overview
- 2 What to Do?
- 3 Use Cases
- 4 Engineering Plan
The ability for extensions to interact directly with the filesystem has been one of the more controversial topics with WebExtensions. In the past this ability has been available to legacy extensions through APIs like OS.File and OS.File.DirectoryIterator and this has allowed those extensions to read and write from the filesystem with no limits.
Firefox is adopting a sandboxed, multi-process model to provide a safer and more secure environment for our users. As this model is implemented over the next several months, the access Firefox has - including the content it processes - to a host operating environment will continue to be reduced.
Extensions are executed within Firefox, and will have similar access restrictions that are enforced by the sandbox model. Providing extensions with the ability to access the filesystem arbitrarily provides a direct challenge to the integrity of the sandbox, and any potential access outside the content sandbox provided via the WebExtension API needs to be carefully considered.
This document was created to clarify this bug.
In current browser products, filesystem access is provided as follows:
While Chrome currently provides the Filesystem Storage API as documented at the Chrome developer site, its use was required explicit user permission and was targeted at Chrome apps primarily. Chrome apps are being phased out of Chrome proper in favor of progressive web apps, and the Filesystem Storage API is being removed as part of that process, and no replacement is planned.
However this API is targeted at Chrome OS and will be removed in Chrome. Currently 1,424 apps out of 37,652 ask for filesystem 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.
File access is provided through the isAllowedFileSchemeAccess API, and allows extensions to read the contents of any file:// locations, as they can other protocols (e.g. http:// and https://), but write access is not provided. Additionally, a user must explicitly permit this behaviour for a given extension through the Chrome preferences pane in chrome://extensions. This API has very low use, with 55 out of approximately 58,000 extensions on the Chrome store using it (as of 03/2017).
Currently there is the File and Directory Entries API, which is a non-standard API based off of Chrome’s implementation. Outside creation and modification of a virtual filesystem for a given app, it permits read access to a file when using an <input> element or drag and drop.
Per above, there are several existing extensions that use OS.File and other APIs to provide direct access to the filesystem. Features that rely on these APIs will no longer function with the shift to WebExtensions exclusively.
Similar to Chrome, Opera supports the isAllowedFileSchemeAccess API, although its support has not been validated. Minimal testing with an extension that made use of this API caused Opera to crash.
Per Microsoft documentation, isAllowedFileSchemeAccess is not supported.
What to Do?
Per above, providing arbitrary filesystem access in WebExtensions is not currently planned. Implementing Filesystem Storage API is also not planned, given the sandboxing concerns outlined and other platforms removing this API in the near future. Any file access should maintain the integrity of Firefox’s sandboxing initiative, and focus on user security and control.
There have been a number of suggestions on how best to approach filesystem access from a general case.
The most popular suggestion for permitting filesystem access is to “just add a big button” that permits users to grant an extension arbitrary filesystem access. This presents a number of challenges, as it is important for users to understand the risk of the permissions they are granting to the extension. An extension with a general permission could read from or write to any content that user has privileges to access, including profile and account information for Firefox and the Operating System. Given the goals of sandboxing, the potential for misuse, and the need to ensure users can make informed decisions and maintain control over what Firefox and its components - including extensions - have access to, this approach is not something that will be considered at this time.
Just copy Chrome
Effectively, this would entail providing isAllowedFileSchemeAccess only, as the Filesystem API will be removed in early 2018. The isAllowedFileSchemeAccess gives read-only access to any file in the operating environment that a user has permission to access, including system files. Neither the isAllowedFileSchemeAccess nor the Filesystem API being considered for implemention at this time as a WebExtension API given the security concerns and planned obsolescence, respectively.
Explicit user interaction
If an extension is going to interact with a specific file and/or directory, that interaction should be performed in a way that is clear and understandable to the user. The focus would be on explicit user actions, like dragging and dropping files, or using a file picker that the user controls exclusively. These are workflows that the user is already familiar with, provides for most of the use cases that have been articulated by developers, and meet the goals of sandboxing and user control. This is the area that WebExtensions API development will focus on.
Accessing file:// in tabs and content scripts
This enables add-ons to read files from the filesystem. Mostly for things like configurations files (uBlock Origin) or data files (ePub Reader).
Chrome: can call file URLs in tabs APIs, e.g.: tabs.create or tabs.update. However it can't then attach content scripts to those tabs so you can't get the content of the file unless you check "Allow file system access". This allows you to open a file:// URL and then through the content script read the contents.
Firefox: cannot call file URLs in tabs APIs, e.g.: tabs.create or tabs.update. Can attach a content script to those tabs. This means that you can't open a file:// URL and then read through the contents, unless you can get the user to open the file:// for you.
iframing file urls
In Chrome the "Allow file system access" allows you to iframe a file:/// URL on an extension page.
The downloads API
It should be noted that Firefox currently implements the downloads API. This allows add-ons to write files and data to the filesystem in a consistent manner with an understandable user interface. Files are only written into the users downloads directory. Further on some operating systems files downloaded in this manner trigger OS level notifications.
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.
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.
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. Currently this is not something we plan to implement.
Some extensions just want somewhere to store data in a profile and have it persist between restarts of Firefox. Example extensions are photo editors. For this we have an indexedDB store. That can store a large amount of data with user permission, although there are limits.
The extension is then able to store, load and manipulate those files efficiently and remain securely inside the WebExtensions and Firefox sandbox.
Drag and drop, file picker support
Drag and drop and file picker support currently exists for providing read access to files and directories. One known limitation is that drag and drop only works on a content element that can receive a file drop event. It would be nice to enable it across the entire browser. This would require modification of content handlers.
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
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