Google Drive Security update - ResourceKeys - google-drive-api

I'm trying to make changes when making API calls to Google drive API because of the security update they will enforce on the 10th September.
In a subset of files, it seems it will be needed to pass a specific header in Google Drive's API requests with the file's resourceKey if the key exists (Name of the header: X-Goog-Drive-Resource-Keys). Info can be found here.
In the docs it is pointed that resource key of a file can be fetched with Google Drive's GET file method.
However from the article is unclear, that if it needs to be the admin of thee file to get that file, store the resource key and all calls afterwards made to that file from another person's perspective needs the resource key, including calling the get file method.
Do we need to pass the resource key to the get file method in Google drive API or can we can fetch the ResourceKey with a user that already had permissions to the file before this security update and use the resource key to all other calls afterwards?

From the link:
A file that is shared with the link can only be discovered by users that can access the file as a result of a type=user or type=group permission. Requests from users that only have access to these link-shared files via a type=domain or type=anyone permission, may require a resource key.
As long as you have the proper (user/group) permissions during the request, you will be able to access it without resource key. You only need it when the user only have the domain/anyone permission. And I think that it will still be needed in the get method if you don't have the proper permissions.
As for the storing the resource key and using it in future requests, that I am not sure as like you said, it wasn't provided in the information. But if the resource key is static (which is likely), then you will most likely be able to reuse it in the next requests.
Additional details here
On September 13, 2021, Drive applies a security update to make file sharing more secure. As an administrator, you can choose how to apply this update.
This update changes the links used for some files. Access to impacted files won’t change for people who have already viewed them or who have direct access, but others might need to request access.

Related

What is the Drive API change on September 13, 2021 about, and what should I respond to?

Last month I got an email from The Google Drive Team.
It's about the Drive API change on September 13, 2021, and I have a question about it.
No matter how much I read, I don't understand what this update is about. Can someone explain in detail?
The Drive API I use now is set to use the save/load function among the settings for Play Game Service in the Google Play Console.
Do I have to respond to this update?
Below is the content of the email received:
Please update your code as detailed below before September 13, 2021, to avoid failing requests.
What do I need to know?
Items that have a Drive API permission with type=domain or type=anyone, where withLink=true (v2) or allowFileDiscovery=false (v3), will be affected by this security update.
In addition to the item ID, your application may now also need a resource key to access these items. Without a resource key, requests for these items may result in a 404 Not Found error (See below for details). Note that access to items that are directly shared with the user or group are not affected.
Will this change affect me?
If your application uses the Drive API to access files which have been shared with a user through link sharing, your application may be affected by this change.
What do I need to do?
To avoid errors accessing files, you must update your code for accessing files to include the appropriate resource keys. Details on how to do this for each of the affected Drive APIs is included below:
Changes to the Drive API
The resource key of an item is returned on the resourceKey field of the file metadata in the Drive API response.
If the file is a shortcut file, then the resource key for the target of the shortcut can be read from the shortcutDetails.targetResourceKey field of the same resource.
URL type fields such as exportLinks, webContentLink, and webViewLink will include the resourceKey.
Requests to the Drive API can specify one or more resource keys with the X-Goog-Drive-Resource-Keys HTTP request header.
Learn more about this change from the Drive API guide.
Changes to Apps Script
The DriveApp from Apps Script has been updated to return the resource key of a file or folder with the getResourceKey method.
Note: When fetching a file or folder, the resource key can be specified on the getFileByIdAndResourceKey or getFolderByIdAndResourceKey methods.
Changes to Drive UI Integrations
If your application is integrated with the Drive UI to create or open items, it will receive resource keys when your application is invoked from the Drive UI.
The state information for a New URL will contain folderResourceKey, which is the resource key of the folder where the new item should be created.
The state for an Open URL will contain a mapping of file ID to resource key in the resourceKeys field.
Learn more about integrating with the Drive UI on our website.
In my opinion, this email was worded very badly as it sounds like Google is telling you that if you don't change your code, things will break. The fact of the matter is Google doesn't know that, only you do.
What is the update
Google Drive is releasing a security update that will apply to some Drive files. The security update will make Google Drive files more secure by updating their links to include a resource key and may lead to some new file access requests.
Find your impacted files
On your computer, go to drive.google.com.
At the top, type: is:security_update_applied or is:security_update_removed in the search bar.
How you may be impacted
Once the security update is applied to a file, a resource key included in the URL will be required to access the file. Users who previously accessed or viewed the file won’t need the resource key in the URL. Only people who haven’t previously accessed the file will need the resource key to gain access. If they don’t have the URL with the resource key, they’ll need to request access to the file.
So if you share the file with someone New then they need to resource key, users who had been grated access previously should be fine.
Will I know if someone can’t access a file I own because they don’t have a link with the resource key?
If someone requests access to one of your files with the security update, you’ll receive an email telling you whether they tried to access your file using an old link. You can then send the person a new link with the resource key so that they can gain access.
So if you do nothing and leave your application as is then, when you try to share a file with someone, you will get an email telling you that there is a problem.
Security update for Google Drive

Drive API update

We got the Drive API update changes last week.
The email content:
Very appreciate if you can help to confirm the following two questions:
We have tried the resourceKey, but it didn't work, is there a specific time for it to take effect?
URL type fields such as exportLinks, webContentLink, and webViewLink
will include the resourceKey.
Currently, we are just using the webViewLink, do we still need to update our code for accessing files to include the appropriate resource keys?
Beginning Monday, September 13, 2021, Google will begin enforcing a security update to Google Drive. Users like you who own or manage impacted files will be notified about the affected files beginning Monday, July 26, 2021.
This security update adds a resource key that makes sharing links from Google Drive files more secure. When file links are updated, users may receive new file access requests. Those who do not have accessed to the files before the update will have to use URLs containing resource keys to access the files.
To avoid broken links, users should update Google Drive links on their websites and shared resources before September 13.
Update Impacts Developers
Affected items are those that have a Drive File API permission with type=domain or type=anyone where withLink=true (v2) or allowFileDiscovery=false (v3).
In addition to the item ID, applications may need a resource key to access files. Use Google’s Developer resource to learn more about how this update will impact your projects.
access
You can also check that the resourceKey security update is already activated in your domain by going to Google Admin.
The effects should have kicked in today, the 13th. So far I'm NOT getting the resourceKey when I call for a file list. Yes, the resourceKey is part of the field list I send. Testing this in https://developers.google.com/drive/api/v3/reference/files/get using * for field list and a file ID that SHOULD be returning a resourceKey there is nothing returned for resourceKey. We are getting 403 errors on certain operation in our code - only place where a direct URL to the Google drive is used.
Essentially we do NOT have the resourceKey supplied to us so there is no way to add it to the URL!
When I checked my test GDrive before the weekend in order to turn this security update ON, the console indicated that it was already turned on, which I had certainly not done!

File.getResourceKey consistently returns null in Google Apps Script

According to a recent email from GoogleDevelopers, it will be necessary to specify a resourceKey when fetching some files and folders after the security update on the 13th of September 2021. They say "To avoid errors accessing files, you must update your code for accessing files to include the appropriate resource keys."
Fetching the key appears to work for folders:
var folder = DriveApp.getFolderById(folderId);
var folderResourceKey = folder.getResourceKey();
If I understand correctly, after the security update it will still be possible for the developer to use this method to fetch the resource key (assuming appropriate sharing settings on the folder). Then we can hardcode the resource key in the script for use in a getFolderByIdAndResourceKey call.
However, when I try this on a File instead of a Folder, I consistently receive "null" for the resource key:
var file = DriveApp.getFileById(fileId);
var resourceKey = file.getResourceKey();
I've tried this for several files, including files which I own and which I created months ago, so I don't think it can be an instance of this issue:
Unpredictable result of DriveId.getResourceId() in Google Drive Android API
The API documentation indicates that it should work the same way for Files as for Folders:
https://developers.google.com/apps-script/reference/drive/file?hl=en#getResourceKey()
https://developers.google.com/apps-script/reference/drive/folder?hl=en#getresourcekey
I also tried getTargetResourceKey in case the files were links, but the result was still null:
https://developers.google.com/apps-script/reference/drive/file?hl=en#gettargetresourcekey
After loading the file in the web browser, I tried clicking on "File -> Document details", but it doesn't show the metadata.
This API document indicates that the resource key is included when you fetch the metadata, but I think the context of this page is different and I can't see how to fetch this metadata from Google Apps Script:
https://developers.google.com/drive/api/v3/reference/files
Even if I can work out the context in which I can fetch that metadata, I don't have much hope that it's going to contain the resource key which is not provided by the GAS API.
Is there any way for the Google Apps Script developer to fetch the resource keys for files?
You can now use getSecurityUpdateEnabled announced on August 31, 2021:
Gets whether this File requires a resource key for access when it's shared using a link. This requirement is turned on by default for eligible files and folders. To turn the resource key requirement on or off for eligible files, use setSecurityUpdateEnabled.
Source: https://developers.google.com/apps-script/reference/drive/file#getsecurityupdateenabled
Use it to check if file requires resource key:
var file = DriveApp.getFileById(fileId);
if (file.getSecurityUpdateEnabled())
{
// resource key is required for the file
// ..
}
Announced methods include methods to get whether files/folders are eligible for security update:
File.getSecurityUpdateEligible() / Folder.getSecurityUpdateEligible()
Announced methods include methods to set whether files/folders require a resource key for access when they shared using a link:
File.setSecurityUpdateEnabled(enabled) / Folder.setSecurityUpdateEnabled(enabled)
General info on why files/folders may return null instead of resource key string:
From current documentation (bold is mine):
Access link-shared files using resource keys
A file that is shared with the link can only be discovered by users that can access the file as a result of a type=user or type=group permission. Requests from users that only have access to these link-shared files via a type=domain or type=anyone permission, may require a resource key.
This resource key requirement only applies to a subset of old files.
For more information about permissions, see Share files, folders and drives.
So, as far as I can tell, there is no indication that each Google Drive file should have non-null resource key, unless it's link-shared with specific permission, and somehow required only for subset of old files.

Google Drive API get AppProperties with API Key

Question:
Is it possible to access the appProperties field in a Google Drive document via an unauthenticated user (i.e., via API Key or other method rather than Oauth)?
Background:
I have an app that works as a live document editor. It authenticates users via OAuth and allows them to save those documents to their google drive, and later re-open them in my app (google file ids are saved in my database and will load the document text into my app). Create()-ing and Get()-ing these files works fine as long as the user is signed in, and I have the "appProperties" field storing a couple of additional key metadata items.
As a next step, I would like to allow users to mark a document as "public view", and provide read-only access to their file, even for non-logged-in users. In my head, the flow would work as follows:
User_A authenticates with OAuth and creates a document, saved to their google drive.
User_A presses a button in my app, which sets the google document to a public sharing mode?
App generates a "viewer" link that User_A can share with his friends.
User_B does not have a Google account, but visits the "viewer link", and my app looks up the appropriate google document (using API key? since User_B is not logged in)
Document is loaded into my app for viewing.
This seems to mostly work; I can read the file metadata just fine using the API key, and even get the file contents. Side Note: Why do we need the API Key at all, given the quote on the google drive api page: "Note: Authorization optional."
However, the "appProperties" field always returns empty when using the API key!
Edit: After further searching I am just more confused. The closest answer I could find was from this related question here on stackoverflow:
It's very simple. appPropperties is a private field and is available only to the application that added it.
Based on this, it seems Google Drive is treating requests from my app API Key and requests from OAuth users on my app as two separate apps?
Further, I would eventually like to allow users to collaborate on a single document, owned by one user. So instead of just providing a read-only "view" link, they could generate an "editor invitation" link that would allow an authenticated user (User_B gets a google account now) to be added as an authorized collaborator (but not simultaneous editing) on the original (User_A's) document. Is that even possible?
Note I am using the Node.js google api.
This might be a bug:
appProperties are app-specific properties attached to a file. Any call from this app should be able to access them. Therefore, I think calls from this app using an API key should be able to retrieve these properties.
I could reproduce this behaviour: appProperties are populated when using OAuth, but not when using an API key, even though both are created from the same GCP project.
I filed a bug:
After researching this issue, I think this might be a bug. Therefore, I decided to file a bug on Issue Tracker:
appProperties are not populated when accessing a public File using an API key
To anyone affected by this, I'd suggest to click the top-left star in order to keep track of this and to help prioritizing it.
Reference:
Add custom file properties

value attribute for Permissions Resource not populated in responses

Looking at:
https://developers.google.com/drive/v2/reference/permissions#resource
the values attribute which contains the email address value for the ACL is not returned by the API. It's not clear why the value isn't returned, I assume it's a privacy issue but it means Drive SDK can't support document migration (from one Google account to another) use cases where the old Documents List API v3 can:
https://developers.google.com/google-apps/documents-list/#retrieving_the_acl_for_a_document_file_or_collection
for now I'm looking at adding both Drive API and Docs v3 API scopes for my project and just using the Docs API call to retrieve the ACLs but ideally I'd be able to use just Drive API calls. Am I missing anything? Could a special scope be added to Drive API that allows ACL email address retrieval or is there some other way to handle this?
Jay
Thanks for your question Jay and thanks your answer Ali Afshar!
Unfortunately I do not understand how Google believes the following scenario should work without the email address of the users:
In Documents List API v3 you could copy a file A to file B, retrieve the ACL-information of file A (including the users email adresses) and simply add them as ACL to file B.
With Drive API you can retrieve almost the same Permission information, but without the user email address, which is still required to re-share file B to the same users.
As a sidenote: If you use GAS DefaultService DocsList, you can still receive the editor/viewers with getEditors() or getViewers(). If you manually share a file you can see all email addresses as well.
So if you ask me, the privacy issue is a valuable argument, but it does simply not apply here.
Jan
Since this question was posted, Drive API has been updated to allow permissionId to be sent on permissions.insert() (the id attribute). This allows for migration of ACLs without ever needing to know the email addresses (just straight copy the permissionIds over to the new file).
Additionally:
the permissions.getIdForEmail() API call provides a quick way to get the ID for a given email address
when returning permissions for a file with permissions.get() or permissions.insert(), the domain attribute is included which should help determine if the ACL raises security concerns.
I believe these features cover most use cases where the actual ACL email address retrieval was needed.
You are absolutely correct, the email address is hidden for privacy. It is not right that a user should see the email addresses of all other users that have access to the file. But I'm not sure I quite get the problem. Are you migrating using service accounts, or are users individually authorizing the migration?
The value in the permissions feed is consistent for each user, and that value is available in the about feed for a user. I assume you know the email address of the users, so you can authorize for each of them With a service account, and you can migrate the data.
You should not need the Drive API scope and the Docs v3 API scope, they are pretty much the same scope.
Also resurrecting this old thread, I had the same issue while migrating documents.
A workaround:
- Create a temporary folder
- Insert a permission for the user
- retrieve the id from the permission
Not nice, but works for me.