WebExtensions/Filesystem: Difference between revisions

From MozillaWiki
Jump to navigation Jump to search
(Created page with "== 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 leg...")
 
(→‎Chrome: Remove repeated word (typo))
 
(5 intermediate revisions by one other user not shown)
Line 1: Line 1:
Status: '''THIS IS A DRAFT, more to come.'''
== Overview ==
== 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  
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 [https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/OSFile.jsm OS.File and OS.File.DirectoryIterator] and this has allowed those extensions to read and write from the filesystem with no limits.
... and this has allowed extensions to read and write from the file system 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.  


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.
This document was created to clarify [https://bugzilla.mozilla.org/show_bug.cgi?id=1246236 this bug].


The main driver of trying to explain this is bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1246236
In current browser products, filesystem access is provided as follows:


=== Chrome ===
=== Chrome ===


Chrome provides the File System Storage API as documented at: https://developer.chrome.com/apps/app_storage  
While Chrome currently provides the Filesystem Storage API as documented at the [https://developer.chrome.com/apps/app_storage 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 [https://developers.google.com/web/progressive-web-apps/ 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 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.  
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.  


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.  
Firefox has not been implementing app APIs for extensions, but only implementing extension APIs.


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.
File access is provided through the [https://developer.chrome.com/extensions/extension#method-isAllowedFileSchemeAccess 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).


=== Firefox ===
=== 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 the [https://developer.mozilla.org/en-US/docs/Web/API/File_and_Directory_Entries_API 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.


==== WebAPI ====
==== Legacy Extensions ====
 
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.
 
==== Opera ====
 
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.
 
==== Edge ====
 
Per [https://docs.microsoft.com/en-us/microsoft-edge/extensions/api-support/supported-apis 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.


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.
There have been a number of suggestions on how best to approach filesystem access from a general case.


==== In the past ====
=== Just add a big button ===


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.
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 a big button ====
=== Just copy Chrome ===


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.
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.


==== 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 ===


===== 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.


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.
== Use Cases ==


=== Opera ===
=== Accessing file:// in tabs and content scripts ===


Opera supports isAllowedFileSchemeAccess, although I haven’t confirmed this. I tried this with an extension and Opera crashed.
This enables add-ons to read files from the filesystem. Mostly for things like configurations files (uBlock Origin) or data files (ePub Reader).


=== Edge ===
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.


Not supported according to the docs: https://docs.microsoft.com/en-us/microsoft-edge/extensions/api-support/supported-apis
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.


== Use Cases ==  
=== iframing file urls ===


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.
In Chrome the "Allow file system access" allows you to iframe a file:/// URL on an extension page.


=== The downloads API ===
=== 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  
It should be noted that Firefox currently implements the [https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/downloads 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.
 
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.
The downloads API is not accessible from the content process, preserving the file system sandboxing requirements.
Line 64: Line 82:
=== Streaming downloads into the downloads directory ===
=== 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:
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 [https://bugzilla.mozilla.org/show_bug.cgi?id=1323414 efficient processing of large downloads] in Firefox.
 
https://bugzilla.mozilla.org/show_bug.cgi?id=1323414  


=== Choosing location in the downloads directory ===
=== 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:
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 [https://bugzilla.mozilla.org/show_bug.cgi?id=1245652 onDeterminingFilename API] that Chrome supports.
 
https://bugzilla.mozilla.org/show_bug.cgi?id=1245652


=== Writing outside the downloads directory ===
=== Writing outside the downloads directory ===
Line 78: Line 92:
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 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.
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.
 
https://bugzilla.mozilla.org/show_bug.cgi?id=1331618


=== Blob storage ===
=== 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.
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, [https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria 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.
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.
We’d like to ensure that a large storage is available, with [https://bugzilla.mozilla.org/show_bug.cgi?id=1331618 appropriate prompting] for the user. We’d like to [https://github.com/mdn/webextensions-examples/pull/171 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 ===
=== 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.
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.
 
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 ==
== Engineering Plan ==

Latest revision as of 22:53, 12 March 2019

Status: THIS IS A DRAFT, more to come.

Overview

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:

Chrome

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).

Firefox

WebAPI

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.

Legacy Extensions

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.

Opera

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.

Edge

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.

Just add a big button

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.

Use Cases

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.

Blob storage

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.

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.

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.

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