-
Notifications
You must be signed in to change notification settings - Fork 65
Add cloud file handling proposal #411
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
75a72a4
Initial commit
alex292 000ab30
Initial commit
alex292 51cdcd9
add proposals/ folder
a-sully 72d2463
Update a reference to FileSystemHandle/entry
a-sully b0a7b0d
assume entry exists if it can be located
a-sully 04f9f12
Move files into proposals/ directory
alex292 3732348
Merge branch 'WICG:main' into cloud-file-handle
alex292 327897b
rename fields
alex292 da88877
Use camelCase for field names
alex292 d2fb20d
Rename CloudFileHandle -> CloudIdentifier
alex292 303d93f
Address review comments
alex292 97114a9
Fix incorrect ```
alex292 077ebdc
Replace readwrite -> edit/write
alex292 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,197 @@ | ||
| # Cloud Identifier | ||
|
|
||
| ## Authors: | ||
|
|
||
| * Alexander Hendrich ([email protected]) | ||
|
|
||
| ## Participate | ||
|
|
||
| * [Issue tracker](https://github.com/WICG/file-system-access/issues) | ||
|
|
||
| ## Table of Contents | ||
|
|
||
| <!-- START doctoc generated TOC please keep comment here to allow auto update --> | ||
| <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --> | ||
|
|
||
| <!-- END doctoc generated TOC please keep comment here to allow auto update --> | ||
|
|
||
| ## Introduction | ||
| The objective of this API is to allow web applications to detect whether a `FileSystemHandle` they have acquired (obtained via file/directory picker or as a parameter of an opening flow as a registered file handler) belongs to a cloud-synced file/directory. If so, the web application receives a “cloud identifier” so that it can directly interact with the file/directory using the cloud storage provider’s (CSP) backend APIs. | ||
|
|
||
| A CSP can register as a local sync client to the browser, which in turn may ask the local sync client to provide a unique identifier for a given file/directory when requested. | ||
|
|
||
| ### Sample usage | ||
|
|
||
| ```javascript | ||
| const [fileHandle] = await window.showOpenFilePicker(pickerOpts); | ||
| const cloudIdentifiers = await fileHandle.getCloudIdentifiers(); | ||
|
|
||
| if(cloudIdentifiers.length === 0) { | ||
| // File is not synced by any CSP | ||
| } | ||
| for(const cloudIdentifier of cloudIdentifiers) { | ||
| if(cloudIdentifier.providerName === 'drive.google.com') { | ||
| // retrieve/modify the file from Google Drive API using cloudIdentifier.id | ||
| } else if(cloudIdentifier.providerName === 'onedrive.live.com') { | ||
| // retrieve/modify the file from Microsoft OneDrive API using cloudIdentifier.id | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Use Cases | ||
|
|
||
| #### Remote file handling | ||
|
|
||
| Web applications offering app streaming or VDI might want to make a locally synced file available to the remote virtual machine where the app/desktop is being streamed from. For example, the user runs their image editor on a remote machine, launches the file picker to open image.png from the local client device, makes some changes and then saves the file with Ctrl+S. | ||
|
|
||
| ##### Before | ||
|
|
||
|  | ||
|
|
||
| 1. VDI web app requests and receives the file via `FileSystemFileHandle.getFile()` | ||
| 2. CSP client app downloads the file from CSP server (if not already on disc) | ||
| 3. VDI web app transfers the file’s content to VDI server, which creates it as local file on the server and opens the application for that file | ||
| 4. VDI server sends any changes made to the file back to the VDI web app | ||
| 5. VDI web app writes updated file contents via `FileSystemFileHandle.write()`, which is picked up by the CSP client app | ||
| 6. CSP client app synchronizes the file by uploading it to the CSP server | ||
|
|
||
| In this scenario all transfers (arrows in diagram) transfer the entire file and the file has to be downloaded and uploaded from the local device’s network connection. | ||
|
|
||
| ##### After | ||
|
|
||
|  | ||
|
|
||
| 1. VDI web app requests and receives the file’s cloud identifier via `FileSystemFileHandle.getCloudIdentifiers()` | ||
| 2. VDI web app sends the file’s cloud identifier to VDI server | ||
| 3. VDI server requests and receives the file’s content from CSP server using the cloud identifier | ||
| 4. VDI server sends any changes made to the file back to the CSP server | ||
| 5. CSP client synchronizes updated file to local device (might be metadata only) | ||
|
|
||
| In this scenario only transfers (3) and (4) would actually transfer the full file, all the other transfers only move the cloud identifier. These actual file transfers also don’t move across the device’s network connection, but rather use the VDI server’s network connection to the CSP server, which should likely also have higher bandwidth. | ||
|
|
||
| This reduces network traffic and delays (especially with large files) and prevents version drift (file being modified somewhere else while a local client device is uploading). | ||
|
|
||
| #### De-duplication for online document editors | ||
|
|
||
| Web-based document editors can already open local files using existing file system APIs. In order to offer full functionality, including cross device support and some advanced editing/sharing features, the documents need to be uploaded to a cloud storage (Google Drive or Microsoft OneDrive or similar) before they can be edited. This leads to duplicate files for documents that were already stored in these locations. | ||
|
|
||
| With the proposed changes, the web application could check whether the given file handle is already synced by a cloud storage and generate identifiers for these without a duplicate upload. | ||
|
|
||
| #### Drag & Drop into Mail | ||
|
|
||
| Sharing files via mail used to be done using simple file attachments. Especially for large files, it is preferable to instead upload them to a CSP and then share an access link to that file to the recipient. Google Mail’s web application, for example, already does this by prompting the user to upload a file to Google Drive when attaching a large file. | ||
|
|
||
| With the proposed changes, the web application could already detect that the file is synced by cloud storage and generate a share link for that file’s cloud identifier without requiring the user to manually go through these steps or prompt the user to upload the file to cloud storage again. | ||
|
|
||
| ### Non-Goals | ||
|
|
||
| This proposal does **not** plan to provide a way for web apps to | ||
| * provide permission to these files/directories. | ||
| * interact (fetch/modify/etc) with these files/directories. | ||
| * provide additional meta-data (e.g. sync status) | ||
|
|
||
| across various different CSP backend APIs. | ||
|
|
||
| This new web API just serves as bridge between the CSP's local sync clients and the web app to retrieve a unique identifier for a file/directory. Obtaining the required permissions on that file/directory or actually reading/writing contents to it via CSP backend API is delegated to the web app's own implementation for each CSP. The `getCloudIdentifiers()` might also return `FileSystemCloudIdentifier`s for CSPs the web app does not support. | ||
|
|
||
| ## Design | ||
|
|
||
|  | ||
|
|
||
| 1. Locally installed CSP client registers itself as a provider for certain directories with the browser | ||
| 2. Web app receives `FileSystemHandle` for a file/directory (via File Handling opening flow, File System Access file/directory picker or drag & drop) and requests its cloud identifier(s) via `getCloudIdentifiers()`. | ||
| 3. Browser checks whether this path has been registered as being synced by a local sync client | ||
| * If no, resolve promise with empty list | ||
| 4. For each registered local sync client for that path, the browser will send a request to the registered local sync client's executable with the file’s/directory’s path | ||
| 5. Local sync client requests a token for that path from the CSP | ||
| 6. CSP can choose to generate a one-time token or stable identifier to later be used by the CSP’s backend APIs. Either way, the properties of the token are up to the CSP and completely opaque to the browser. | ||
| 7. Local sync client responds to browser with the token | ||
| 8. Browser gathers all responses from registered local sync clients. For all incoming responses, the browser will construct a cloud identifier consisting of the responding local sync client's registered identifier and the provided token. Once all registered local sync clients for that path have responded, the promise is resolved with a list of cloud identifiers. If the local sync client fails to respond within a reasonable time frame, the promise is resolved with all received cloud identifiers until then or empty list if none. | ||
| 9. Web app can freely interact with CSP’s backend APIs on that file/directory. The web application is responsible for getting the right access permissions for these web APIs. | ||
|
|
||
| ### Web IDL | ||
|
|
||
| This section describes the interface the web app would interact with. | ||
|
|
||
| ```idl | ||
| dictionary FileSystemCloudIdentifier { | ||
| DOMString providerName; | ||
| DOMString id; | ||
| }; | ||
|
|
||
| partial interface FileSystemHandle { | ||
| Promise<FileSystemCloudIdentifier[]> getCloudIdentifiers(); | ||
| } | ||
| ``` | ||
|
|
||
| The new method | ||
| * extends `FileSystemHandle`, i.e. is available for files and directories. | ||
| * returns a list of `FileSystemCloudIdentifier`s since a single file/directory can be synced by multiple CSPs at the same time, although in most cases this list would only contain a single entry. | ||
| * returns an empty list if the file/directory is not synced by any CSPs or no CSP client responded in time. | ||
|
|
||
| ### Interaction with CSP client | ||
|
|
||
| This web API requires the browser and the CSP’s local sync client to exchange information. This piece is not part of the official specification and up to individual browser’s to implement, but we can provide guidelines here as well. | ||
|
|
||
| #### Registration | ||
|
|
||
| The browser needs to be aware of | ||
| * which CSP client’s are available on the user’s computer | ||
| * which files/directories are synced by the CSP client | ||
| * where the CSP client executable is located | ||
| * the CSP’s identifier (e.g. “com.google.drive”) | ||
|
|
||
| Therefore, the CSP needs to provide a JSON file containing these details and register it with the browser at a known location (specific directory or registry key), similar to [Chrome extension’s native messaging host registration](https://developer.chrome.com/docs/apps/nativeMessaging/#native-messaging-host-location). | ||
|
|
||
| The provided file would look like this: | ||
|
|
||
| ```json | ||
| { | ||
| "name": "com.foo-company.drive", | ||
| "path": "C:\\Program Files\\FooCompany\\cloud_storage_provider_helper.exe", | ||
| "synced_paths": [ | ||
| "C:\\path_to_synced_directory\\", | ||
| "C:\\path_to_other_synced_directory\\", | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| #### Requesting a cloud identifier | ||
|
|
||
| Whenever a web app calls `getCloudIdentifiers()`, the browser will iterate through all registered CSP clients and filter for ones that cover the file’s/directory’s path as part of their `synced_paths`. | ||
|
|
||
| For these, the browser will launch the executable at `path` and transfer the web app’s origin and the requested file/directory path, either via command line argument or via stdin (preceded with a 32-bit message length). | ||
|
|
||
| The CSP client will then respond with the token for the given file/directory via stdout (preceded with a 32-bit message length). | ||
|
|
||
| Once the browser has received all responses (or some reasonable timeout has expired), the browser will bundle the individual tokens and the CSPs’ names together to return a cloud identifier. | ||
|
|
||
| It is up to each individual browser’s implementation on how they handle dynamic registrations, i.e. whether they re-read all the CSP registration files for each request and how long or if they cache them. | ||
|
|
||
| ## Security and Privacy Considerations | ||
|
|
||
| ### Fingerprinting | ||
|
|
||
| The browser has no control whether the CSP will provide one-time tokens or stable identifiers as part of their cloud identifier. If the CSP provides stable identifiers, the web application could use these as a [fingerprinting](https://www.w3.org/TR/fingerprinting-guidance/#dfn-active-fingerprinting) mechanism for the files/directories it has access to. | ||
|
|
||
| In theory, if a web application already has access to a `FileSystemHandle` the web application could already use other mechanisms to generate fingerprinting identifiers, but these are less stable: | ||
| * Hashing the file’s/directory’s contents -> identifier will change if file/directory content changes | ||
| * `FileSystemHandle.getUniqueId()` [[explainer](https://github.com/whatwg/fs/pull/46)] -> clearing browsing data will reset unique IDs | ||
|
|
||
| The web application would need repeated access to the same `FileSystemHandle` to perform this fingerprinting though. That means the user must either re-grant access to the same file or the web app stores the file handle in an IndexedDB, which can be cleared by the user though by clearing their browsing data. | ||
|
|
||
| It would also be up to the CSP whether they actually provide permanent tokens or temporary tokens. | ||
|
|
||
| ### Modification via read-only permission | ||
|
|
||
| If a web application only has `read` [permission](https://wicg.github.io/file-system-access/#enumdef-filesystempermissionmode) to a `FileSystemHandle`, but has edit/write permission to that file via CSP backend APIs, it could still modify the cloud-stored file, which is then synced to the device and thereby modify the file. | ||
|
|
||
| In this case, the user has clearly granted write access to the CSP-backed file and by having a sync client, the user also allows the local files to be modified, so the change would actually not be surprising. | ||
|
|
||
| ## Contributors | ||
|
|
||
| * Austin Sullivan ([email protected]) | ||
| * Rob Beard ([email protected]) | ||
|
|
||
| ## Stakeholder Feedback / Opposition | ||
| TBD | ||
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.